/* * 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 org.apache.harmony.luni.util; public final class NumberConverter { private int setCount; // number of times u and k have been gotten private int getCount; // number of times u and k have been set private int[] uArray = new int[64]; private int firstK; private final static double invLogOfTenBaseTwo = Math.log(2.0) / Math.log(10.0); private final static long[] TEN_TO_THE = new long[20]; static { TEN_TO_THE[0] = 1L; for (int i = 1; i < TEN_TO_THE.length; ++i) { long previous = TEN_TO_THE[i - 1]; TEN_TO_THE[i] = (previous << 1) + (previous << 3); } } private static NumberConverter getConverter() { return new NumberConverter(); } public static String convert(double input) { return getConverter().convertD(input); } public static String convert(float input) { return getConverter().convertF(input); } public String convertD(double inputNumber) { int p = 1023 + 52; // the power offset (precision) long signMask = 0x8000000000000000L; // the mask to get the sign of // the number long eMask = 0x7FF0000000000000L; // the mask to get the power bits long fMask = 0x000FFFFFFFFFFFFFL; // the mask to get the significand // bits long inputNumberBits = Double.doubleToLongBits(inputNumber); // the value of the sign... 0 is positive, ~0 is negative String signString = (inputNumberBits & signMask) == 0 ? "" : "-"; // the value of the 'power bits' of the inputNumber int e = (int) ((inputNumberBits & eMask) >> 52); // the value of the 'significand bits' of the inputNumber long f = inputNumberBits & fMask; boolean mantissaIsZero = f == 0; int pow = 0, numBits = 52; if (e == 2047) return mantissaIsZero ? signString + "Infinity" : "NaN"; if (e == 0) { if (mantissaIsZero) return signString + "0.0"; if (f == 1) // special case to increase precision even though 2 * // Double.MIN_VALUE is 1.0e-323 return signString + "4.9E-324"; 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; } if (-59 < pow && pow < 6 || (pow == -59 && !mantissaIsZero)) longDigitGenerator(f, pow, e == 0, mantissaIsZero, numBits); else bigIntDigitGeneratorInstImpl(f, pow, e == 0, mantissaIsZero, numBits); if (inputNumber >= 1e7D || inputNumber <= -1e7D || (inputNumber > -1e-3D && inputNumber < 1e-3D)) return signString + freeFormatExponential(); return signString + freeFormat(); } public String convertF(float inputNumber) { int p = 127 + 23; // the power offset (precision) int signMask = 0x80000000; // the mask to get the sign of the number int eMask = 0x7F800000; // the mask to get the power bits int fMask = 0x007FFFFF; // the mask to get the significand bits int inputNumberBits = Float.floatToIntBits(inputNumber); // the value of the sign... 0 is positive, ~0 is negative String signString = (inputNumberBits & signMask) == 0 ? "" : "-"; // the value of the 'power bits' of the inputNumber int e = (inputNumberBits & eMask) >> 23; // the value of the 'significand bits' of the inputNumber int f = inputNumberBits & fMask; boolean mantissaIsZero = f == 0; int pow = 0, numBits = 23; if (e == 255) return mantissaIsZero ? signString + "Infinity" : "NaN"; if (e == 0) { if (mantissaIsZero) return signString + "0.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; } if (-59 < pow && pow < 35 || (pow == -59 && !mantissaIsZero)) longDigitGenerator(f, pow, e == 0, mantissaIsZero, numBits); else bigIntDigitGeneratorInstImpl(f, pow, e == 0, mantissaIsZero, numBits); if (inputNumber >= 1e7f || inputNumber <= -1e7f || (inputNumber > -1e-3f && inputNumber < 1e-3f)) return signString + freeFormatExponential(); return signString + freeFormat(); } private String freeFormatExponential() { // corresponds to process "Free-Format Exponential" char[] formattedDecimal = new char[25]; formattedDecimal[0] = (char) ('0' + uArray[getCount++]); formattedDecimal[1] = '.'; // the position the next character is to be inserted into // formattedDecimal int charPos = 2; int k = firstK; int expt = k; while (true) { k--; if (getCount >= setCount) break; formattedDecimal[charPos++] = (char) ('0' + uArray[getCount++]); } if (k == expt - 1) formattedDecimal[charPos++] = '0'; formattedDecimal[charPos++] = 'E'; return new String(formattedDecimal, 0, charPos) + Integer.toString(expt); } private String freeFormat() { // corresponds to process "Free-Format" char[] formattedDecimal = new char[25]; // the position the next character is to be inserted into // formattedDecimal int charPos = 0; int k = firstK; if (k < 0) { formattedDecimal[0] = '0'; formattedDecimal[1] = '.'; charPos += 2; for (int i = k + 1; i < 0; i++) formattedDecimal[charPos++] = '0'; } int U = uArray[getCount++]; do { if (U != -1) formattedDecimal[charPos++] = (char) ('0' + U); else if (k >= -1) formattedDecimal[charPos++] = '0'; if (k == 0) formattedDecimal[charPos++] = '.'; k--; U = getCount < setCount ? uArray[getCount++] : -1; } while (U != -1 || k >= -1); return new String(formattedDecimal, 0, charPos); } private native void bigIntDigitGeneratorInstImpl(long f, int e, boolean isDenormalized, boolean mantissaIsZero, 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 * TEN_TO_THE[k]; } else if (k < 0) { long scale = TEN_TO_THE[-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; } getCount = setCount = 0; // reset indices boolean low, high; int U; long[] Si = new long[] { S, S << 1, S << 2, S << 3 }; while (true) { // set U to be floor (R / S) and R to be the remainder // using a kind of "binary search" to find the answer. // It's a lot quicker than actually dividing since we know // the answer will be between 0 and 10 U = 0; long remainder; for (int i = 3; i >= 0; i--) { remainder = R - Si[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; uArray[setCount++] = U; } if (low && !high) uArray[setCount++] = U; else if (high && !low) uArray[setCount++] = U + 1; else if ((R << 1) < S) uArray[setCount++] = U; else uArray[setCount++] = U + 1; } }