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
18706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughespackage java.lang;
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughesimport libcore.math.MathUtils;
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
22706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughesfinal class RealToString {
2330ae871abe462723f78b2981178a9d5a73f5e129Elliott Hughes    private static final ThreadLocal<RealToString> INSTANCE = new ThreadLocal<RealToString>() {
2430ae871abe462723f78b2981178a9d5a73f5e129Elliott Hughes        @Override protected RealToString initialValue() {
2530ae871abe462723f78b2981178a9d5a73f5e129Elliott Hughes            return new RealToString();
2630ae871abe462723f78b2981178a9d5a73f5e129Elliott Hughes        }
2730ae871abe462723f78b2981178a9d5a73f5e129Elliott Hughes    };
2830ae871abe462723f78b2981178a9d5a73f5e129Elliott Hughes
2930ae871abe462723f78b2981178a9d5a73f5e129Elliott Hughes    private static final double invLogOfTenBaseTwo = Math.log(2.0) / Math.log(10.0);
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
3110a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes    private int firstK;
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
3310a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes    /**
3410a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes     * An array of decimal digits, filled by longDigitGenerator or bigIntDigitGenerator.
3510a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes     */
3610a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes    private final int[] digits = new int[64];
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
3810a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes    /**
3910a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes     * Number of valid entries in 'digits'.
4010a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes     */
4110a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes    private int digitCount;
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
4310a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes    private RealToString() {
4410a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes    }
4510a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes
4610a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes    public static RealToString getInstance() {
4710a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes        return INSTANCE.get();
4810a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes    }
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
50620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes    private static String resultOrSideEffect(AbstractStringBuilder sb, String s) {
51620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes        if (sb != null) {
52620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes            sb.append0(s);
53620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes            return null;
54620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes        }
55620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes        return s;
56620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes    }
57620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes
58620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes    public String doubleToString(double d) {
59620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes        return convertDouble(null, d);
60620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes    }
61620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes
62620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes    public void appendDouble(AbstractStringBuilder sb, double d) {
63620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes        convertDouble(sb, d);
64620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes    }
65620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes
66620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes    private String convertDouble(AbstractStringBuilder sb, double inputNumber) {
6710a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes        long inputNumberBits = Double.doubleToRawLongBits(inputNumber);
68706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        boolean positive = (inputNumberBits & Double.SIGN_MASK) == 0;
69706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        int e = (int) ((inputNumberBits & Double.EXPONENT_MASK) >> Double.MANTISSA_BITS);
70706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        long f = inputNumberBits & Double.MANTISSA_MASK;
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        boolean mantissaIsZero = f == 0;
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
73620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes        String quickResult = null;
74706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        if (e == 2047) {
75620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes            if (mantissaIsZero) {
76620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes                quickResult = positive ? "Infinity" : "-Infinity";
77620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes            } else {
78620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes                quickResult = "NaN";
79620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes            }
80620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes        } else if (e == 0) {
81620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes            if (mantissaIsZero) {
82620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes                quickResult = positive ? "0.0" : "-0.0";
83620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes            } else if (f == 1) {
84620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes                // special case to increase precision even though 2 * Double.MIN_VALUE is 1.0e-323
85620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes                quickResult = positive ? "4.9E-324" : "-4.9E-324";
86706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes            }
87706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        }
88620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes        if (quickResult != null) {
89620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes            return resultOrSideEffect(sb, quickResult);
90620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes        }
91620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes
92706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        int p = Double.EXPONENT_BIAS + Double.MANTISSA_BITS; // the power offset (precision)
9330ae871abe462723f78b2981178a9d5a73f5e129Elliott Hughes        int pow;
9430ae871abe462723f78b2981178a9d5a73f5e129Elliott Hughes        int numBits = Double.MANTISSA_BITS;
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (e == 0) {
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            pow = 1 - p; // a denormalized number
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            long ff = f;
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while ((ff & 0x0010000000000000L) == 0) {
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                ff = ff << 1;
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                numBits--;
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // 0 < e < 2047
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // a "normalized" number
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            f = f | 0x0010000000000000L;
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            pow = e - p;
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
10910a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes        firstK = digitCount = 0;
110706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        if (-59 < pow && pow < 6 || (pow == -59 && !mantissaIsZero)) {
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            longDigitGenerator(f, pow, e == 0, mantissaIsZero, numBits);
112706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        } else {
113706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes            bigIntDigitGenerator(f, pow, e == 0, numBits);
114706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        }
115620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes        AbstractStringBuilder dst = (sb != null) ? sb : new StringBuilder(26);
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (inputNumber >= 1e7D || inputNumber <= -1e7D
117706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes                || (inputNumber > -1e-3D && inputNumber < 1e-3D)) {
118620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes            freeFormatExponential(dst, positive);
119620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes        } else {
120620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes            freeFormat(dst, positive);
121706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        }
122620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes        return (sb != null) ? null : dst.toString();
123620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes    }
124620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes
125620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes    public String floatToString(float f) {
126620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes        return convertFloat(null, f);
127620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes    }
128620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes
129620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes    public void appendFloat(AbstractStringBuilder sb, float f) {
130620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes        convertFloat(sb, f);
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
133620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes    public String convertFloat(AbstractStringBuilder sb, float inputNumber) {
13410a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes        int inputNumberBits = Float.floatToRawIntBits(inputNumber);
135706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        boolean positive = (inputNumberBits & Float.SIGN_MASK) == 0;
136706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        int e = (inputNumberBits & Float.EXPONENT_MASK) >> Float.MANTISSA_BITS;
137706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        int f = inputNumberBits & Float.MANTISSA_MASK;
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        boolean mantissaIsZero = f == 0;
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
140620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes        String quickResult = null;
141706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        if (e == 255) {
142620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes            if (mantissaIsZero) {
143620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes                quickResult = positive ? "Infinity" : "-Infinity";
144620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes            } else {
145620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes                quickResult = "NaN";
146706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes            }
147620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes        } else if (e == 0 && mantissaIsZero) {
148620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes            quickResult = positive ? "0.0" : "-0.0";
149620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes        }
150620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes        if (quickResult != null) {
151620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes            return resultOrSideEffect(sb, quickResult);
152706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        }
153620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes
154706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        int p = Float.EXPONENT_BIAS + Float.MANTISSA_BITS; // the power offset (precision)
15530ae871abe462723f78b2981178a9d5a73f5e129Elliott Hughes        int pow;
15630ae871abe462723f78b2981178a9d5a73f5e129Elliott Hughes        int numBits = Float.MANTISSA_BITS;
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (e == 0) {
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            pow = 1 - p; // a denormalized number
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (f < 8) { // want more precision with smallest values
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                f = f << 2;
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                pow -= 2;
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int ff = f;
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while ((ff & 0x00800000) == 0) {
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                ff = ff << 1;
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                numBits--;
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // 0 < e < 255
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // a "normalized" number
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            f = f | 0x00800000;
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            pow = e - p;
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
17510a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes        firstK = digitCount = 0;
176706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        if (-59 < pow && pow < 35 || (pow == -59 && !mantissaIsZero)) {
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            longDigitGenerator(f, pow, e == 0, mantissaIsZero, numBits);
178706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        } else {
179706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes            bigIntDigitGenerator(f, pow, e == 0, numBits);
180706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        }
181620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes        AbstractStringBuilder dst = (sb != null) ? sb : new StringBuilder(26);
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (inputNumber >= 1e7f || inputNumber <= -1e7f
183706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes                || (inputNumber > -1e-3f && inputNumber < 1e-3f)) {
184620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes            freeFormatExponential(dst, positive);
185620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes        } else {
186620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes            freeFormat(dst, positive);
187706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        }
188620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes        return (sb != null) ? null : dst.toString();
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
191620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes    private void freeFormatExponential(AbstractStringBuilder sb, boolean positive) {
19210a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes        int digitIndex = 0;
193706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        if (!positive) {
194620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes            sb.append0('-');
195706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        }
196620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes        sb.append0((char) ('0' + digits[digitIndex++]));
197620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes        sb.append0('.');
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int k = firstK;
20010a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes        int exponent = k;
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (true) {
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            k--;
20310a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes            if (digitIndex >= digitCount) {
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
205706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes            }
206620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes            sb.append0((char) ('0' + digits[digitIndex++]));
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20910a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes        if (k == exponent - 1) {
210620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes            sb.append0('0');
211706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        }
212620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes        sb.append0('E');
213620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes        IntegralToString.appendInt(sb, exponent);
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
216620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes    private void freeFormat(AbstractStringBuilder sb, boolean positive) {
21710a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes        int digitIndex = 0;
218706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        if (!positive) {
219620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes            sb.append0('-');
220706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        }
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int k = firstK;
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (k < 0) {
223620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes            sb.append0('0');
224620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes            sb.append0('.');
225706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes            for (int i = k + 1; i < 0; ++i) {
226620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes                sb.append0('0');
227706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes            }
228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
22910a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes        int U = digits[digitIndex++];
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        do {
231706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes            if (U != -1) {
232620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes                sb.append0((char) ('0' + U));
233706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes            } else if (k >= -1) {
234620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes                sb.append0('0');
235706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes            }
236706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes            if (k == 0) {
237620666783267ed3a6f7f2b4309a66f1c1f18de53Elliott Hughes                sb.append0('.');
238706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes            }
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            k--;
24010a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes            U = digitIndex < digitCount ? digits[digitIndex++] : -1;
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } while (U != -1 || k >= -1);
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
244706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes    private native void bigIntDigitGenerator(long f, int e, boolean isDenormalized, int p);
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void longDigitGenerator(long f, int e, boolean isDenormalized,
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            boolean mantissaIsZero, int p) {
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        long R, S, M;
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (e >= 0) {
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            M = 1l << e;
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!mantissaIsZero) {
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                R = f << (e + 1);
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                S = 2;
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                R = f << (e + 2);
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                S = 4;
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            M = 1;
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (isDenormalized || !mantissaIsZero) {
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                R = f << 1;
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                S = 1l << (1 - e);
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                R = f << 2;
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                S = 1l << (2 - e);
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int k = (int) Math.ceil((e + p - 1) * invLogOfTenBaseTwo - 1e-10);
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (k > 0) {
272706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes            S = S * MathUtils.LONG_POWERS_OF_TEN[k];
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else if (k < 0) {
274706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes            long scale = MathUtils.LONG_POWERS_OF_TEN[-k];
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            R = R * scale;
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            M = M == 1 ? scale : M * scale;
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (R + M > S) { // was M_plus
280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            firstK = k;
281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            firstK = k - 1;
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            R = R * 10;
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            M = M * 10;
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        boolean low, high;
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int U;
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (true) {
29030ae871abe462723f78b2981178a9d5a73f5e129Elliott Hughes            // Set U to floor(R/S) and R to the remainder, using *unsigned* 64-bit division
29130ae871abe462723f78b2981178a9d5a73f5e129Elliott Hughes            U = 0;
29230ae871abe462723f78b2981178a9d5a73f5e129Elliott Hughes            for (int i = 3; i >= 0; i--) {
29330ae871abe462723f78b2981178a9d5a73f5e129Elliott Hughes                long remainder = R - (S << i);
29430ae871abe462723f78b2981178a9d5a73f5e129Elliott Hughes                if (remainder >= 0) {
29530ae871abe462723f78b2981178a9d5a73f5e129Elliott Hughes                    R = remainder;
29630ae871abe462723f78b2981178a9d5a73f5e129Elliott Hughes                    U += 1 << i;
29730ae871abe462723f78b2981178a9d5a73f5e129Elliott Hughes                }
29830ae871abe462723f78b2981178a9d5a73f5e129Elliott Hughes            }
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            low = R < M; // was M_minus
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            high = R + M > S; // was M_plus
302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
303706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes            if (low || high) {
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
305706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes            }
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            R = R * 10;
307adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            M = M * 10;
30810a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes            digits[digitCount++] = U;
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
310706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        if (low && !high) {
31110a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes            digits[digitCount++] = U;
312706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        } else if (high && !low) {
31310a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes            digits[digitCount++] = U + 1;
314706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        } else if ((R << 1) < S) {
31510a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes            digits[digitCount++] = U;
316706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        } else {
31710a17e23b22dc0ff6363d15bce67d668b6d44dd0Elliott Hughes            digits[digitCount++] = U + 1;
318706de1164836051ab31cc69eb77a6bba1a723896Elliott Hughes        }
319adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
321