1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  the License.  You may obtain a copy of the License at
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  See the License for the specific language governing permissions and
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  limitations under the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18dc915c69ba2495dd2cf965d16058d0b13762142cElliott Hughespackage java.lang;
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.regex.Matcher;
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.regex.Pattern;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Parses hex string to a single or double precision floating point number.
25dc915c69ba2495dd2cf965d16058d0b13762142cElliott Hughes *
26dc915c69ba2495dd2cf965d16058d0b13762142cElliott Hughes * TODO: rewrite this!
27dc915c69ba2495dd2cf965d16058d0b13762142cElliott Hughes *
28dc915c69ba2495dd2cf965d16058d0b13762142cElliott Hughes * @hide
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectfinal class HexStringParser {
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final int DOUBLE_EXPONENT_WIDTH = 11;
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final int DOUBLE_MANTISSA_WIDTH = 52;
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final int FLOAT_EXPONENT_WIDTH = 8;
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final int FLOAT_MANTISSA_WIDTH = 23;
39f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final int HEX_RADIX = 16;
41f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final int MAX_SIGNIFICANT_LENGTH = 15;
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
44f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes    private static final String HEX_SIGNIFICANT = "0[xX](\\p{XDigit}+\\.?|\\p{XDigit}*\\.\\p{XDigit}+)";
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
46f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes    private static final String BINARY_EXPONENT = "[pP]([+-]?\\d+)";
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
48f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes    private static final String FLOAT_TYPE_SUFFIX = "[fFdD]?";
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
50f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes    private static final String HEX_PATTERN = "[\\x00-\\x20]*([+-]?)" + HEX_SIGNIFICANT
51f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            + BINARY_EXPONENT + FLOAT_TYPE_SUFFIX + "[\\x00-\\x20]*";
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final Pattern PATTERN = Pattern.compile(HEX_PATTERN);
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private final int EXPONENT_WIDTH;
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private final int MANTISSA_WIDTH;
58f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private final long EXPONENT_BASE;
60f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private final long MAX_EXPONENT;
62f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private final long MIN_EXPONENT;
64f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private final long MANTISSA_MASK;
66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private long sign;
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private long exponent;
70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private long mantissa;
72f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
73f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes    private String abandonedNumber="";
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
759229d47c1288e25ead3a2dc27fac8a4a2ee932a3Elliott Hughes    public HexStringParser(int exponentWidth, int mantissaWidth) {
769229d47c1288e25ead3a2dc27fac8a4a2ee932a3Elliott Hughes        this.EXPONENT_WIDTH = exponentWidth;
779229d47c1288e25ead3a2dc27fac8a4a2ee932a3Elliott Hughes        this.MANTISSA_WIDTH = mantissaWidth;
78f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
799229d47c1288e25ead3a2dc27fac8a4a2ee932a3Elliott Hughes        this.EXPONENT_BASE = ~(-1L << (exponentWidth - 1));
809229d47c1288e25ead3a2dc27fac8a4a2ee932a3Elliott Hughes        this.MAX_EXPONENT = ~(-1L << exponentWidth);
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.MIN_EXPONENT = -(MANTISSA_WIDTH + 1);
829229d47c1288e25ead3a2dc27fac8a4a2ee932a3Elliott Hughes        this.MANTISSA_MASK = ~(-1L << mantissaWidth);
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Parses the hex string to a double number.
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static double parseDouble(String hexString) {
891f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        HexStringParser parser = new HexStringParser(DOUBLE_EXPONENT_WIDTH, DOUBLE_MANTISSA_WIDTH);
901f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        long result = parser.parse(hexString, true);
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return Double.longBitsToDouble(result);
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Parses the hex string to a float number.
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static float parseFloat(String hexString) {
981f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        HexStringParser parser = new HexStringParser(FLOAT_EXPONENT_WIDTH, FLOAT_MANTISSA_WIDTH);
991f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        int result = (int) parser.parse(hexString, false);
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return Float.intBitsToFloat(result);
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1031f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes    private long parse(String hexString, boolean isDouble) {
1041f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        Matcher matcher = PATTERN.matcher(hexString);
1051f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        if (!matcher.matches()) {
1061f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes            throw new NumberFormatException("Invalid hex " + (isDouble ? "double" : "float")+ ":" +
1071f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes                    hexString);
1081f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        }
1091f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes
1101f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        String signStr = matcher.group(1);
1111f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        String significantStr = matcher.group(2);
1121f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes        String exponentStr = matcher.group(3);
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        parseHexSign(signStr);
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        parseExponent(exponentStr);
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        parseMantissa(significantStr);
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        sign <<= (MANTISSA_WIDTH + EXPONENT_WIDTH);
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        exponent <<= MANTISSA_WIDTH;
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return sign | exponent | mantissa;
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Parses the sign field.
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void parseHexSign(String signStr) {
127f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        this.sign = signStr.equals("-") ? 1 : 0;
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Parses the exponent field.
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void parseExponent(String exponentStr) {
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        char leadingChar = exponentStr.charAt(0);
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int expSign = (leadingChar == '-' ? -1 : 1);
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (!Character.isDigit(leadingChar)) {
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            exponentStr = exponentStr.substring(1);
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            exponent = expSign * Long.parseLong(exponentStr);
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            checkedAddExponent(EXPONENT_BASE);
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (NumberFormatException e) {
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            exponent = expSign * Long.MAX_VALUE;
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
147f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Parses the mantissa field.
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void parseMantissa(String significantStr) {
152f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        String[] strings = significantStr.split("\\.");
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String strIntegerPart = strings[0];
154f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        String strDecimalPart = strings.length > 1 ? strings[1] : "";
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String significand = getNormalizedSignificand(strIntegerPart,strDecimalPart);
157f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        if (significand.equals("0")) {
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            setZero();
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int offset = getOffset(strIntegerPart, strDecimalPart);
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        checkedAddExponent(offset);
164f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (exponent >= MAX_EXPONENT) {
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            setInfinite();
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
169f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (exponent <= MIN_EXPONENT) {
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            setZero();
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (significand.length() > MAX_SIGNIFICANT_LENGTH) {
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            abandonedNumber = significand.substring(MAX_SIGNIFICANT_LENGTH);
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            significand = significand.substring(0, MAX_SIGNIFICANT_LENGTH);
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        mantissa = Long.parseLong(significand, HEX_RADIX);
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (exponent >= 1) {
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            processNormalNumber();
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else{
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            processSubNormalNumber();
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
189f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void setInfinite() {
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        exponent = MAX_EXPONENT;
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        mantissa = 0;
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void setZero() {
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        exponent = 0;
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        mantissa = 0;
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
199f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Sets the exponent variable to Long.MAX_VALUE or -Long.MAX_VALUE if
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * overflow or underflow happens.
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void checkedAddExponent(long offset) {
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        long result = exponent + offset;
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int expSign = Long.signum(exponent);
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (expSign * Long.signum(offset) > 0 && expSign * Long.signum(result) < 0) {
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            exponent = expSign * Long.MAX_VALUE;
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            exponent = result;
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
213f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void processNormalNumber(){
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int desiredWidth = MANTISSA_WIDTH + 2;
216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        fitMantissaInDesiredWidth(desiredWidth);
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        round();
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        mantissa = mantissa & MANTISSA_MASK;
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
220f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void processSubNormalNumber(){
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int desiredWidth = MANTISSA_WIDTH + 1;
223adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        desiredWidth += (int)exponent;//lends bit from mantissa to exponent
224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        exponent = 0;
225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        fitMantissaInDesiredWidth(desiredWidth);
226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        round();
227adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        mantissa = mantissa & MANTISSA_MASK;
228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
229f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Adjusts the mantissa to desired width for further analysis.
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void fitMantissaInDesiredWidth(int desiredWidth){
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int bitLength = countBitsLength(mantissa);
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (bitLength > desiredWidth) {
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            discardTrailingBits(bitLength - desiredWidth);
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            mantissa <<= (desiredWidth - bitLength);
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
241f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Stores the discarded bits to abandonedNumber.
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void discardTrailingBits(long num) {
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        long mask = ~(-1L << num);
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        abandonedNumber += (mantissa & mask);
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        mantissa >>= num;
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The value is rounded up or down to the nearest infinitely precise result.
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * If the value is exactly halfway between two infinitely precise results,
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * then it should be rounded up to the nearest infinitely precise even.
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void round() {
257f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        String result = abandonedNumber.replaceAll("0+", "");
258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        boolean moreThanZero = (result.length() > 0 ? true : false);
259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int lastDiscardedBit = (int) (mantissa & 1L);
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        mantissa >>= 1;
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int tailBitInMantissa = (int) (mantissa & 1L);
263f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (lastDiscardedBit == 1 && (moreThanZero || tailBitInMantissa == 1)) {
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int oldLength = countBitsLength(mantissa);
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            mantissa += 1L;
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int newLength = countBitsLength(mantissa);
268f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            //Rounds up to exponent when whole bits of mantissa are one-bits.
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (oldLength >= MANTISSA_WIDTH && newLength > oldLength) {
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                checkedAddExponent(1);
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the normalized significand after removing the leading zeros.
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private String getNormalizedSignificand(String strIntegerPart, String strDecimalPart) {
280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String significand = strIntegerPart + strDecimalPart;
281f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        significand = significand.replaceFirst("^0+", "");
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (significand.length() == 0) {
283f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            significand = "0";
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return significand;
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Calculates the offset between the normalized number and unnormalized
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * number. In a normalized representation, significand is represented by the
291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * characters "0x1." followed by a lowercase hexadecimal representation of
292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * the rest of the significand as a fraction.
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private int getOffset(String strIntegerPart, String strDecimalPart) {
295f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        strIntegerPart = strIntegerPart.replaceFirst("^0+", "");
296f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
297f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        //If the Integer part is a nonzero number.
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (strIntegerPart.length() != 0) {
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String leadingNumber = strIntegerPart.substring(0, 1);
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return (strIntegerPart.length() - 1) * 4 + countBitsLength(Long.parseLong(leadingNumber,HEX_RADIX)) - 1;
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
302f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
303f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        //If the Integer part is a zero number.
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int i;
305f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        for (i = 0; i < strDecimalPart.length() && strDecimalPart.charAt(i) == '0'; i++);
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (i == strDecimalPart.length()) {
307adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return 0;
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String leadingNumber=strDecimalPart.substring(i,i + 1);
310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return (-i - 1) * 4 + countBitsLength(Long.parseLong(leadingNumber, HEX_RADIX)) - 1;
311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
313adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private int countBitsLength(long value) {
314adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int leadingZeros = Long.numberOfLeadingZeros(value);
315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return Long.SIZE - leadingZeros;
316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
318