/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package java.lang; import libcore.math.MathUtils; final class RealToString { private static final ThreadLocal<RealToString> INSTANCE = new ThreadLocal<RealToString>() { @Override protected RealToString initialValue() { return new RealToString(); } }; private static final double invLogOfTenBaseTwo = Math.log(2.0) / Math.log(10.0); private int firstK; /** * An array of decimal digits, filled by longDigitGenerator or bigIntDigitGenerator. */ private final int[] digits = new int[64]; /** * Number of valid entries in 'digits'. */ private int digitCount; private RealToString() { } public static RealToString getInstance() { return INSTANCE.get(); } private static String resultOrSideEffect(AbstractStringBuilder sb, String s) { if (sb != null) { sb.append0(s); return null; } return s; } public String doubleToString(double d) { return convertDouble(null, d); } public void appendDouble(AbstractStringBuilder sb, double d) { convertDouble(sb, d); } private String convertDouble(AbstractStringBuilder sb, double inputNumber) { long inputNumberBits = Double.doubleToRawLongBits(inputNumber); boolean positive = (inputNumberBits & Double.SIGN_MASK) == 0; int e = (int) ((inputNumberBits & Double.EXPONENT_MASK) >> Double.MANTISSA_BITS); long f = inputNumberBits & Double.MANTISSA_MASK; boolean mantissaIsZero = f == 0; String quickResult = null; if (e == 2047) { if (mantissaIsZero) { quickResult = positive ? "Infinity" : "-Infinity"; } else { quickResult = "NaN"; } } else if (e == 0) { if (mantissaIsZero) { quickResult = positive ? "0.0" : "-0.0"; } else if (f == 1) { // special case to increase precision even though 2 * Double.MIN_VALUE is 1.0e-323 quickResult = positive ? "4.9E-324" : "-4.9E-324"; } } if (quickResult != null) { return resultOrSideEffect(sb, quickResult); } int p = Double.EXPONENT_BIAS + Double.MANTISSA_BITS; // the power offset (precision) int pow; int numBits = Double.MANTISSA_BITS; if (e == 0) { pow = 1 - p; // a denormalized number long ff = f; while ((ff & 0x0010000000000000L) == 0) { ff = ff << 1; numBits--; } } else { // 0 < e < 2047 // a "normalized" number f = f | 0x0010000000000000L; pow = e - p; } firstK = digitCount = 0; if (-59 < pow && pow < 6 || (pow == -59 && !mantissaIsZero)) { longDigitGenerator(f, pow, e == 0, mantissaIsZero, numBits); } else { bigIntDigitGenerator(f, pow, e == 0, numBits); } AbstractStringBuilder dst = (sb != null) ? sb : new StringBuilder(26); if (inputNumber >= 1e7D || inputNumber <= -1e7D || (inputNumber > -1e-3D && inputNumber < 1e-3D)) { freeFormatExponential(dst, positive); } else { freeFormat(dst, positive); } return (sb != null) ? null : dst.toString(); } public String floatToString(float f) { return convertFloat(null, f); } public void appendFloat(AbstractStringBuilder sb, float f) { convertFloat(sb, f); } public String convertFloat(AbstractStringBuilder sb, float inputNumber) { int inputNumberBits = Float.floatToRawIntBits(inputNumber); boolean positive = (inputNumberBits & Float.SIGN_MASK) == 0; int e = (inputNumberBits & Float.EXPONENT_MASK) >> Float.MANTISSA_BITS; int f = inputNumberBits & Float.MANTISSA_MASK; boolean mantissaIsZero = f == 0; String quickResult = null; if (e == 255) { if (mantissaIsZero) { quickResult = positive ? "Infinity" : "-Infinity"; } else { quickResult = "NaN"; } } else if (e == 0 && mantissaIsZero) { quickResult = positive ? "0.0" : "-0.0"; } if (quickResult != null) { return resultOrSideEffect(sb, quickResult); } int p = Float.EXPONENT_BIAS + Float.MANTISSA_BITS; // the power offset (precision) int pow; int numBits = Float.MANTISSA_BITS; if (e == 0) { pow = 1 - p; // a denormalized number if (f < 8) { // want more precision with smallest values f = f << 2; pow -= 2; } int ff = f; while ((ff & 0x00800000) == 0) { ff = ff << 1; numBits--; } } else { // 0 < e < 255 // a "normalized" number f = f | 0x00800000; pow = e - p; } firstK = digitCount = 0; if (-59 < pow && pow < 35 || (pow == -59 && !mantissaIsZero)) { longDigitGenerator(f, pow, e == 0, mantissaIsZero, numBits); } else { bigIntDigitGenerator(f, pow, e == 0, numBits); } AbstractStringBuilder dst = (sb != null) ? sb : new StringBuilder(26); if (inputNumber >= 1e7f || inputNumber <= -1e7f || (inputNumber > -1e-3f && inputNumber < 1e-3f)) { freeFormatExponential(dst, positive); } else { freeFormat(dst, positive); } return (sb != null) ? null : dst.toString(); } private void freeFormatExponential(AbstractStringBuilder sb, boolean positive) { int digitIndex = 0; if (!positive) { sb.append0('-'); } sb.append0((char) ('0' + digits[digitIndex++])); sb.append0('.'); int k = firstK; int exponent = k; while (true) { k--; if (digitIndex >= digitCount) { break; } sb.append0((char) ('0' + digits[digitIndex++])); } if (k == exponent - 1) { sb.append0('0'); } sb.append0('E'); IntegralToString.appendInt(sb, exponent); } private void freeFormat(AbstractStringBuilder sb, boolean positive) { int digitIndex = 0; if (!positive) { sb.append0('-'); } int k = firstK; if (k < 0) { sb.append0('0'); sb.append0('.'); for (int i = k + 1; i < 0; ++i) { sb.append0('0'); } } int U = digits[digitIndex++]; do { if (U != -1) { sb.append0((char) ('0' + U)); } else if (k >= -1) { sb.append0('0'); } if (k == 0) { sb.append0('.'); } k--; U = digitIndex < digitCount ? digits[digitIndex++] : -1; } while (U != -1 || k >= -1); } private native void bigIntDigitGenerator(long f, int e, boolean isDenormalized, int p); private void longDigitGenerator(long f, int e, boolean isDenormalized, boolean mantissaIsZero, int p) { long R, S, M; if (e >= 0) { M = 1l << e; if (!mantissaIsZero) { R = f << (e + 1); S = 2; } else { R = f << (e + 2); S = 4; } } else { M = 1; if (isDenormalized || !mantissaIsZero) { R = f << 1; S = 1l << (1 - e); } else { R = f << 2; S = 1l << (2 - e); } } int k = (int) Math.ceil((e + p - 1) * invLogOfTenBaseTwo - 1e-10); if (k > 0) { S = S * MathUtils.LONG_POWERS_OF_TEN[k]; } else if (k < 0) { long scale = MathUtils.LONG_POWERS_OF_TEN[-k]; R = R * scale; M = M == 1 ? scale : M * scale; } if (R + M > S) { // was M_plus firstK = k; } else { firstK = k - 1; R = R * 10; M = M * 10; } boolean low, high; int U; while (true) { // Set U to floor(R/S) and R to the remainder, using *unsigned* 64-bit division U = 0; for (int i = 3; i >= 0; i--) { long remainder = R - (S << i); if (remainder >= 0) { R = remainder; U += 1 << i; } } low = R < M; // was M_minus high = R + M > S; // was M_plus if (low || high) { break; } R = R * 10; M = M * 10; digits[digitCount++] = U; } if (low && !high) { digits[digitCount++] = U; } else if (high && !low) { digits[digitCount++] = U + 1; } else if ((R << 1) < S) { digits[digitCount++] = U; } else { digits[digitCount++] = U + 1; } } }