| /* | |
| * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. Oracle designates this | |
| * particular file as subject to the "Classpath" exception as provided | |
| * by Oracle in the LICENSE file that accompanied this code. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| package jdk.internal.math; | |
| import jdk.internal.vm.annotation.Stable; | |
| import java.util.Arrays; | |
| /** | |
| * A class for converting between ASCII and decimal representations of a single | |
| * or double precision floating point number. Most conversions are provided via | |
| * static convenience methods, although a <code>BinaryToASCIIConverter</code> | |
| * instance may be obtained and reused. | |
| */ | |
| public class FloatingDecimal{ | |
| // | |
| // Constants of the implementation; | |
| // most are IEEE-754 related. | |
| // (There are more really boring constants at the end.) | |
| // | |
| static final int EXP_SHIFT = DoubleConsts.SIGNIFICAND_WIDTH - 1; | |
| static final long FRACT_HOB = ( 1L<<EXP_SHIFT ); // assumed High-Order bit | |
| static final long EXP_ONE = ((long)DoubleConsts.EXP_BIAS)<<EXP_SHIFT; // exponent of 1.0 | |
| static final int MAX_SMALL_BIN_EXP = 62; | |
| static final int MIN_SMALL_BIN_EXP = -( 63 / 3 ); | |
| static final int MAX_DECIMAL_DIGITS = 15; | |
| static final int MAX_DECIMAL_EXPONENT = 308; | |
| static final int MIN_DECIMAL_EXPONENT = -324; | |
| static final int MAX_NDIGITS = 1100; | |
| static final int SINGLE_EXP_SHIFT = FloatConsts.SIGNIFICAND_WIDTH - 1; | |
| static final int SINGLE_FRACT_HOB = 1<<SINGLE_EXP_SHIFT; | |
| static final int SINGLE_MAX_DECIMAL_DIGITS = 7; | |
| static final int SINGLE_MAX_DECIMAL_EXPONENT = 38; | |
| static final int SINGLE_MIN_DECIMAL_EXPONENT = -45; | |
| static final int SINGLE_MAX_NDIGITS = 200; | |
| static final int INT_DECIMAL_DIGITS = 9; | |
| /** | |
| * Converts a double precision floating point value to a <code>String</code>. | |
| * | |
| * @param d The double precision value. | |
| * @return The value converted to a <code>String</code>. | |
| */ | |
| public static String toJavaFormatString(double d) { | |
| return getBinaryToASCIIConverter(d).toJavaFormatString(); | |
| } | |
| /** | |
| * Converts a single precision floating point value to a <code>String</code>. | |
| * | |
| * @param f The single precision value. | |
| * @return The value converted to a <code>String</code>. | |
| */ | |
| public static String toJavaFormatString(float f) { | |
| return getBinaryToASCIIConverter(f).toJavaFormatString(); | |
| } | |
| /** | |
| * Appends a double precision floating point value to an <code>Appendable</code>. | |
| * @param d The double precision value. | |
| * @param buf The <code>Appendable</code> with the value appended. | |
| */ | |
| public static void appendTo(double d, Appendable buf) { | |
| getBinaryToASCIIConverter(d).appendTo(buf); | |
| } | |
| /** | |
| * Appends a single precision floating point value to an <code>Appendable</code>. | |
| * @param f The single precision value. | |
| * @param buf The <code>Appendable</code> with the value appended. | |
| */ | |
| public static void appendTo(float f, Appendable buf) { | |
| getBinaryToASCIIConverter(f).appendTo(buf); | |
| } | |
| /** | |
| * Converts a <code>String</code> to a double precision floating point value. | |
| * | |
| * @param s The <code>String</code> to convert. | |
| * @return The double precision value. | |
| * @throws NumberFormatException If the <code>String</code> does not | |
| * represent a properly formatted double precision value. | |
| */ | |
| public static double parseDouble(String s) throws NumberFormatException { | |
| return readJavaFormatString(s, BINARY_64_IX).doubleValue(); | |
| } | |
| /** | |
| * Converts a <code>String</code> to a single precision floating point value. | |
| * | |
| * @param s The <code>String</code> to convert. | |
| * @return The single precision value. | |
| * @throws NumberFormatException If the <code>String</code> does not | |
| * represent a properly formatted single precision value. | |
| */ | |
| public static float parseFloat(String s) throws NumberFormatException { | |
| return readJavaFormatString(s, BINARY_32_IX).floatValue(); | |
| } | |
| /** | |
| * A converter which can process single or double precision floating point | |
| * values into an ASCII <code>String</code> representation. | |
| */ | |
| public interface BinaryToASCIIConverter { | |
| /** | |
| * Converts a floating point value into an ASCII <code>String</code>. | |
| * @return The value converted to a <code>String</code>. | |
| */ | |
| String toJavaFormatString(); | |
| /** | |
| * Appends a floating point value to an <code>Appendable</code>. | |
| * @param buf The <code>Appendable</code> to receive the value. | |
| */ | |
| void appendTo(Appendable buf); | |
| /** | |
| * Retrieves the decimal exponent most closely corresponding to this value. | |
| * @return The decimal exponent. | |
| */ | |
| int getDecimalExponent(); | |
| /** | |
| * Retrieves the value as an array of digits. | |
| * @param digits The digit array. | |
| * @return The number of valid digits copied into the array. | |
| */ | |
| int getDigits(char[] digits); | |
| /** | |
| * Indicates the sign of the value. | |
| * @return {@code value < 0.0}. | |
| */ | |
| boolean isNegative(); | |
| /** | |
| * Indicates whether the value is either infinite or not a number. | |
| * | |
| * @return <code>true</code> if and only if the value is <code>NaN</code> | |
| * or infinite. | |
| */ | |
| boolean isExceptional(); | |
| /** | |
| * Indicates whether the value was rounded up during the binary to ASCII | |
| * conversion. | |
| * | |
| * @return <code>true</code> if and only if the value was rounded up. | |
| */ | |
| boolean digitsRoundedUp(); | |
| /** | |
| * Indicates whether the binary to ASCII conversion was exact. | |
| * | |
| * @return <code>true</code> if any only if the conversion was exact. | |
| */ | |
| boolean decimalDigitsExact(); | |
| } | |
| /** | |
| * A <code>BinaryToASCIIConverter</code> which represents <code>NaN</code> | |
| * and infinite values. | |
| */ | |
| private static class ExceptionalBinaryToASCIIBuffer implements BinaryToASCIIConverter { | |
| private final String image; | |
| private final boolean isNegative; | |
| public ExceptionalBinaryToASCIIBuffer(String image, boolean isNegative) { | |
| this.image = image; | |
| this.isNegative = isNegative; | |
| } | |
| @Override | |
| public String toJavaFormatString() { | |
| return image; | |
| } | |
| @Override | |
| public void appendTo(Appendable buf) { | |
| if (buf instanceof StringBuilder) { | |
| ((StringBuilder) buf).append(image); | |
| } else if (buf instanceof StringBuffer) { | |
| ((StringBuffer) buf).append(image); | |
| } else { | |
| assert false; | |
| } | |
| } | |
| @Override | |
| public int getDecimalExponent() { | |
| throw new IllegalArgumentException("Exceptional value does not have an exponent"); | |
| } | |
| @Override | |
| public int getDigits(char[] digits) { | |
| throw new IllegalArgumentException("Exceptional value does not have digits"); | |
| } | |
| @Override | |
| public boolean isNegative() { | |
| return isNegative; | |
| } | |
| @Override | |
| public boolean isExceptional() { | |
| return true; | |
| } | |
| @Override | |
| public boolean digitsRoundedUp() { | |
| throw new IllegalArgumentException("Exceptional value is not rounded"); | |
| } | |
| @Override | |
| public boolean decimalDigitsExact() { | |
| throw new IllegalArgumentException("Exceptional value is not exact"); | |
| } | |
| } | |
| private static final String INFINITY_REP = "Infinity"; | |
| private static final String NAN_REP = "NaN"; | |
| private static final BinaryToASCIIConverter B2AC_POSITIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer(INFINITY_REP, false); | |
| private static final BinaryToASCIIConverter B2AC_NEGATIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer("-" + INFINITY_REP, true); | |
| private static final BinaryToASCIIConverter B2AC_NOT_A_NUMBER = new ExceptionalBinaryToASCIIBuffer(NAN_REP, false); | |
| private static final BinaryToASCIIConverter B2AC_POSITIVE_ZERO = new BinaryToASCIIBuffer(false, new char[]{'0'}); | |
| private static final BinaryToASCIIConverter B2AC_NEGATIVE_ZERO = new BinaryToASCIIBuffer(true, new char[]{'0'}); | |
| /** | |
| * A buffered implementation of <code>BinaryToASCIIConverter</code>. | |
| */ | |
| static class BinaryToASCIIBuffer implements BinaryToASCIIConverter { | |
| private boolean isNegative; | |
| private int decExponent; | |
| private int firstDigitIndex; | |
| private int nDigits; | |
| private final char[] digits; | |
| private final char[] buffer = new char[26]; | |
| // | |
| // The fields below provide additional information about the result of | |
| // the binary to decimal digits conversion done in dtoa() and roundup() | |
| // methods. They are changed if needed by those two methods. | |
| // | |
| // True if the dtoa() binary to decimal conversion was exact. | |
| private boolean exactDecimalConversion = false; | |
| // True if the result of the binary to decimal conversion was rounded-up | |
| // at the end of the conversion process, i.e. roundUp() method was called. | |
| private boolean decimalDigitsRoundedUp = false; | |
| /** | |
| * Default constructor; used for non-zero values, | |
| * <code>BinaryToASCIIBuffer</code> may be thread-local and reused | |
| */ | |
| BinaryToASCIIBuffer(){ | |
| this.digits = new char[20]; | |
| } | |
| /** | |
| * Creates a specialized value (positive and negative zeros). | |
| */ | |
| BinaryToASCIIBuffer(boolean isNegative, char[] digits){ | |
| this.isNegative = isNegative; | |
| this.decExponent = 0; | |
| this.digits = digits; | |
| this.firstDigitIndex = 0; | |
| this.nDigits = digits.length; | |
| } | |
| @Override | |
| public String toJavaFormatString() { | |
| int len = getChars(buffer); | |
| return new String(buffer, 0, len); | |
| } | |
| @Override | |
| public void appendTo(Appendable buf) { | |
| int len = getChars(buffer); | |
| if (buf instanceof StringBuilder) { | |
| ((StringBuilder) buf).append(buffer, 0, len); | |
| } else if (buf instanceof StringBuffer) { | |
| ((StringBuffer) buf).append(buffer, 0, len); | |
| } else { | |
| assert false; | |
| } | |
| } | |
| @Override | |
| public int getDecimalExponent() { | |
| return decExponent; | |
| } | |
| @Override | |
| public int getDigits(char[] digits) { | |
| System.arraycopy(this.digits, firstDigitIndex, digits, 0, this.nDigits); | |
| return this.nDigits; | |
| } | |
| @Override | |
| public boolean isNegative() { | |
| return isNegative; | |
| } | |
| @Override | |
| public boolean isExceptional() { | |
| return false; | |
| } | |
| @Override | |
| public boolean digitsRoundedUp() { | |
| return decimalDigitsRoundedUp; | |
| } | |
| @Override | |
| public boolean decimalDigitsExact() { | |
| return exactDecimalConversion; | |
| } | |
| private void setSign(boolean isNegative) { | |
| this.isNegative = isNegative; | |
| } | |
| /** | |
| * This is the easy subcase -- | |
| * all the significant bits, after scaling, are held in lvalue. | |
| * negSign and decExponent tell us what processing and scaling | |
| * has already been done. Exceptional cases have already been | |
| * stripped out. | |
| * In particular: | |
| * lvalue is a finite number (not Inf, nor NaN) | |
| * lvalue > 0L (not zero, nor negative). | |
| * | |
| * The only reason that we develop the digits here, rather than | |
| * calling on Long.toString() is that we can do it a little faster, | |
| * and besides want to treat trailing 0s specially. If Long.toString | |
| * changes, we should re-evaluate this strategy! | |
| */ | |
| private void developLongDigits( int decExponent, long lvalue, int insignificantDigits ){ | |
| if ( insignificantDigits != 0 ){ | |
| // Discard non-significant low-order bits, while rounding, | |
| // up to insignificant value. | |
| long pow10 = FDBigInteger.LONG_5_POW[insignificantDigits] << insignificantDigits; // 10^i == 5^i * 2^i; | |
| long residue = lvalue % pow10; | |
| lvalue /= pow10; | |
| decExponent += insignificantDigits; | |
| if ( residue >= (pow10>>1) ){ | |
| // round up based on the low-order bits we're discarding | |
| lvalue++; | |
| } | |
| } | |
| int digitno = digits.length -1; | |
| int c; | |
| if ( lvalue <= Integer.MAX_VALUE ){ | |
| assert lvalue > 0L : lvalue; // lvalue <= 0 | |
| // even easier subcase! | |
| // can do int arithmetic rather than long! | |
| int ivalue = (int)lvalue; | |
| c = ivalue%10; | |
| ivalue /= 10; | |
| while ( c == 0 ){ | |
| decExponent++; | |
| c = ivalue%10; | |
| ivalue /= 10; | |
| } | |
| while ( ivalue != 0){ | |
| digits[digitno--] = (char)(c+'0'); | |
| decExponent++; | |
| c = ivalue%10; | |
| ivalue /= 10; | |
| } | |
| digits[digitno] = (char)(c+'0'); | |
| } else { | |
| // same algorithm as above (same bugs, too ) | |
| // but using long arithmetic. | |
| c = (int)(lvalue%10L); | |
| lvalue /= 10L; | |
| while ( c == 0 ){ | |
| decExponent++; | |
| c = (int)(lvalue%10L); | |
| lvalue /= 10L; | |
| } | |
| while ( lvalue != 0L ){ | |
| digits[digitno--] = (char)(c+'0'); | |
| decExponent++; | |
| c = (int)(lvalue%10L); | |
| lvalue /= 10; | |
| } | |
| digits[digitno] = (char)(c+'0'); | |
| } | |
| this.decExponent = decExponent+1; | |
| this.firstDigitIndex = digitno; | |
| this.nDigits = this.digits.length - digitno; | |
| } | |
| private void dtoa( int binExp, long fractBits, int nSignificantBits, boolean isCompatibleFormat) | |
| { | |
| assert fractBits > 0 ; // fractBits here can't be zero or negative | |
| assert (fractBits & FRACT_HOB)!=0 ; // Hi-order bit should be set | |
| // Examine number. Determine if it is an easy case, | |
| // which we can do pretty trivially using float/long conversion, | |
| // or whether we must do real work. | |
| final int tailZeros = Long.numberOfTrailingZeros(fractBits); | |
| // number of significant bits of fractBits; | |
| final int nFractBits = EXP_SHIFT+1-tailZeros; | |
| // reset flags to default values as dtoa() does not always set these | |
| // flags and a prior call to dtoa() might have set them to incorrect | |
| // values with respect to the current state. | |
| decimalDigitsRoundedUp = false; | |
| exactDecimalConversion = false; | |
| // number of significant bits to the right of the point. | |
| int nTinyBits = Math.max( 0, nFractBits - binExp - 1 ); | |
| if ( binExp <= MAX_SMALL_BIN_EXP && binExp >= MIN_SMALL_BIN_EXP ){ | |
| // Look more closely at the number to decide if, | |
| // with scaling by 10^nTinyBits, the result will fit in | |
| // a long. | |
| if ( (nTinyBits < FDBigInteger.LONG_5_POW.length) && ((nFractBits + N_5_BITS[nTinyBits]) < 64 ) ){ | |
| // | |
| // We can do this: | |
| // take the fraction bits, which are normalized. | |
| // (a) nTinyBits == 0: Shift left or right appropriately | |
| // to align the binary point at the extreme right, i.e. | |
| // where a long int point is expected to be. The integer | |
| // result is easily converted to a string. | |
| // (b) nTinyBits > 0: Shift right by EXP_SHIFT-nFractBits, | |
| // which effectively converts to long and scales by | |
| // 2^nTinyBits. Then multiply by 5^nTinyBits to | |
| // complete the scaling. We know this won't overflow | |
| // because we just counted the number of bits necessary | |
| // in the result. The integer you get from this can | |
| // then be converted to a string pretty easily. | |
| // | |
| if ( nTinyBits == 0 ) { | |
| int insignificant; | |
| if ( binExp > nSignificantBits ){ | |
| insignificant = insignificantDigitsForPow2(binExp-nSignificantBits-1); | |
| } else { | |
| insignificant = 0; | |
| } | |
| if ( binExp >= EXP_SHIFT ){ | |
| fractBits <<= (binExp-EXP_SHIFT); | |
| } else { | |
| fractBits >>>= (EXP_SHIFT-binExp) ; | |
| } | |
| developLongDigits( 0, fractBits, insignificant ); | |
| return; | |
| } | |
| // | |
| // The following causes excess digits to be printed | |
| // out in the single-float case. Our manipulation of | |
| // halfULP here is apparently not correct. If we | |
| // better understand how this works, perhaps we can | |
| // use this special case again. But for the time being, | |
| // we do not. | |
| // else { | |
| // fractBits >>>= EXP_SHIFT+1-nFractBits; | |
| // fractBits//= long5pow[ nTinyBits ]; | |
| // halfULP = long5pow[ nTinyBits ] >> (1+nSignificantBits-nFractBits); | |
| // developLongDigits( -nTinyBits, fractBits, insignificantDigits(halfULP) ); | |
| // return; | |
| // } | |
| // | |
| } | |
| } | |
| // | |
| // This is the hard case. We are going to compute large positive | |
| // integers B and S and integer decExp, s.t. | |
| // d = ( B / S )// 10^decExp | |
| // 1 <= B / S < 10 | |
| // Obvious choices are: | |
| // decExp = floor( log10(d) ) | |
| // B = d// 2^nTinyBits// 10^max( 0, -decExp ) | |
| // S = 10^max( 0, decExp)// 2^nTinyBits | |
| // (noting that nTinyBits has already been forced to non-negative) | |
| // I am also going to compute a large positive integer | |
| // M = (1/2^nSignificantBits)// 2^nTinyBits// 10^max( 0, -decExp ) | |
| // i.e. M is (1/2) of the ULP of d, scaled like B. | |
| // When we iterate through dividing B/S and picking off the | |
| // quotient bits, we will know when to stop when the remainder | |
| // is <= M. | |
| // | |
| // We keep track of powers of 2 and powers of 5. | |
| // | |
| int decExp = estimateDecExp(fractBits,binExp); | |
| int B2, B5; // powers of 2 and powers of 5, respectively, in B | |
| int S2, S5; // powers of 2 and powers of 5, respectively, in S | |
| int M2, M5; // powers of 2 and powers of 5, respectively, in M | |
| B5 = Math.max( 0, -decExp ); | |
| B2 = B5 + nTinyBits + binExp; | |
| S5 = Math.max( 0, decExp ); | |
| S2 = S5 + nTinyBits; | |
| M5 = B5; | |
| M2 = B2 - nSignificantBits; | |
| // | |
| // the long integer fractBits contains the (nFractBits) interesting | |
| // bits from the mantissa of d ( hidden 1 added if necessary) followed | |
| // by (EXP_SHIFT+1-nFractBits) zeros. In the interest of compactness, | |
| // I will shift out those zeros before turning fractBits into a | |
| // FDBigInteger. The resulting whole number will be | |
| // d * 2^(nFractBits-1-binExp). | |
| // | |
| fractBits >>>= tailZeros; | |
| B2 -= nFractBits-1; | |
| int common2factor = Math.min( B2, S2 ); | |
| B2 -= common2factor; | |
| S2 -= common2factor; | |
| M2 -= common2factor; | |
| // | |
| // HACK!! For exact powers of two, the next smallest number | |
| // is only half as far away as we think (because the meaning of | |
| // ULP changes at power-of-two bounds) for this reason, we | |
| // hack M2. Hope this works. | |
| // | |
| if ( nFractBits == 1 ) { | |
| M2 -= 1; | |
| } | |
| if ( M2 < 0 ){ | |
| // oops. | |
| // since we cannot scale M down far enough, | |
| // we must scale the other values up. | |
| B2 -= M2; | |
| S2 -= M2; | |
| M2 = 0; | |
| } | |
| // | |
| // Construct, Scale, iterate. | |
| // Some day, we'll write a stopping test that takes | |
| // account of the asymmetry of the spacing of floating-point | |
| // numbers below perfect powers of 2 | |
| // 26 Sept 96 is not that day. | |
| // So we use a symmetric test. | |
| // | |
| int ndigit = 0; | |
| boolean low, high; | |
| long lowDigitDifference; | |
| int q; | |
| // | |
| // Detect the special cases where all the numbers we are about | |
| // to compute will fit in int or long integers. | |
| // In these cases, we will avoid doing FDBigInteger arithmetic. | |
| // We use the same algorithms, except that we "normalize" | |
| // our FDBigIntegers before iterating. This is to make division easier, | |
| // as it makes our fist guess (quotient of high-order words) | |
| // more accurate! | |
| // | |
| // Some day, we'll write a stopping test that takes | |
| // account of the asymmetry of the spacing of floating-point | |
| // numbers below perfect powers of 2 | |
| // 26 Sept 96 is not that day. | |
| // So we use a symmetric test. | |
| // | |
| // binary digits needed to represent B, approx. | |
| int Bbits = nFractBits + B2 + (( B5 < N_5_BITS.length )? N_5_BITS[B5] : ( B5*3 )); | |
| // binary digits needed to represent 10*S, approx. | |
| int tenSbits = S2+1 + (( (S5+1) < N_5_BITS.length )? N_5_BITS[(S5+1)] : ( (S5+1)*3 )); | |
| if ( Bbits < 64 && tenSbits < 64){ | |
| if ( Bbits < 32 && tenSbits < 32){ | |
| // wa-hoo! They're all ints! | |
| int b = ((int)fractBits * FDBigInteger.SMALL_5_POW[B5] ) << B2; | |
| int s = FDBigInteger.SMALL_5_POW[S5] << S2; | |
| int m = FDBigInteger.SMALL_5_POW[M5] << M2; | |
| int tens = s * 10; | |
| // | |
| // Unroll the first iteration. If our decExp estimate | |
| // was too high, our first quotient will be zero. In this | |
| // case, we discard it and decrement decExp. | |
| // | |
| ndigit = 0; | |
| q = b / s; | |
| b = 10 * ( b % s ); | |
| m *= 10; | |
| low = (b < m ); | |
| high = (b+m > tens ); | |
| assert q < 10 : q; // excessively large digit | |
| if ( (q == 0) && ! high ){ | |
| // oops. Usually ignore leading zero. | |
| decExp--; | |
| } else { | |
| digits[ndigit++] = (char)('0' + q); | |
| } | |
| // | |
| // HACK! Java spec sez that we always have at least | |
| // one digit after the . in either F- or E-form output. | |
| // Thus we will need more than one digit if we're using | |
| // E-form | |
| // | |
| if ( !isCompatibleFormat ||decExp < -3 || decExp >= 8 ){ | |
| high = low = false; | |
| } | |
| while( ! low && ! high ){ | |
| q = b / s; | |
| b = 10 * ( b % s ); | |
| m *= 10; | |
| assert q < 10 : q; // excessively large digit | |
| if ( m > 0L ){ | |
| low = (b < m ); | |
| high = (b+m > tens ); | |
| } else { | |
| // hack -- m might overflow! | |
| // in this case, it is certainly > b, | |
| // which won't | |
| // and b+m > tens, too, since that has overflowed | |
| // either! | |
| low = true; | |
| high = true; | |
| } | |
| digits[ndigit++] = (char)('0' + q); | |
| } | |
| lowDigitDifference = (b<<1) - tens; | |
| exactDecimalConversion = (b == 0); | |
| } else { | |
| // still good! they're all longs! | |
| long b = (fractBits * FDBigInteger.LONG_5_POW[B5] ) << B2; | |
| long s = FDBigInteger.LONG_5_POW[S5] << S2; | |
| long m = FDBigInteger.LONG_5_POW[M5] << M2; | |
| long tens = s * 10L; | |
| // | |
| // Unroll the first iteration. If our decExp estimate | |
| // was too high, our first quotient will be zero. In this | |
| // case, we discard it and decrement decExp. | |
| // | |
| ndigit = 0; | |
| q = (int) ( b / s ); | |
| b = 10L * ( b % s ); | |
| m *= 10L; | |
| low = (b < m ); | |
| high = (b+m > tens ); | |
| assert q < 10 : q; // excessively large digit | |
| if ( (q == 0) && ! high ){ | |
| // oops. Usually ignore leading zero. | |
| decExp--; | |
| } else { | |
| digits[ndigit++] = (char)('0' + q); | |
| } | |
| // | |
| // HACK! Java spec sez that we always have at least | |
| // one digit after the . in either F- or E-form output. | |
| // Thus we will need more than one digit if we're using | |
| // E-form | |
| // | |
| if ( !isCompatibleFormat || decExp < -3 || decExp >= 8 ){ | |
| high = low = false; | |
| } | |
| while( ! low && ! high ){ | |
| q = (int) ( b / s ); | |
| b = 10 * ( b % s ); | |
| m *= 10; | |
| assert q < 10 : q; // excessively large digit | |
| if ( m > 0L ){ | |
| low = (b < m ); | |
| high = (b+m > tens ); | |
| } else { | |
| // hack -- m might overflow! | |
| // in this case, it is certainly > b, | |
| // which won't | |
| // and b+m > tens, too, since that has overflowed | |
| // either! | |
| low = true; | |
| high = true; | |
| } | |
| digits[ndigit++] = (char)('0' + q); | |
| } | |
| lowDigitDifference = (b<<1) - tens; | |
| exactDecimalConversion = (b == 0); | |
| } | |
| } else { | |
| // | |
| // We really must do FDBigInteger arithmetic. | |
| // Fist, construct our FDBigInteger initial values. | |
| // | |
| FDBigInteger Sval = FDBigInteger.valueOfPow52(S5, S2); | |
| int shiftBias = Sval.getNormalizationBias(); | |
| Sval = Sval.leftShift(shiftBias); // normalize so that division works better | |
| FDBigInteger Bval = FDBigInteger.valueOfMulPow52(fractBits, B5, B2 + shiftBias); | |
| FDBigInteger Mval = FDBigInteger.valueOfPow52(M5 + 1, M2 + shiftBias + 1); | |
| FDBigInteger tenSval = FDBigInteger.valueOfPow52(S5 + 1, S2 + shiftBias + 1); //Sval.mult( 10 ); | |
| // | |
| // Unroll the first iteration. If our decExp estimate | |
| // was too high, our first quotient will be zero. In this | |
| // case, we discard it and decrement decExp. | |
| // | |
| ndigit = 0; | |
| q = Bval.quoRemIteration( Sval ); | |
| low = (Bval.cmp( Mval ) < 0); | |
| high = tenSval.addAndCmp(Bval,Mval)<=0; | |
| assert q < 10 : q; // excessively large digit | |
| if ( (q == 0) && ! high ){ | |
| // oops. Usually ignore leading zero. | |
| decExp--; | |
| } else { | |
| digits[ndigit++] = (char)('0' + q); | |
| } | |
| // | |
| // HACK! Java spec sez that we always have at least | |
| // one digit after the . in either F- or E-form output. | |
| // Thus we will need more than one digit if we're using | |
| // E-form | |
| // | |
| if (!isCompatibleFormat || decExp < -3 || decExp >= 8 ){ | |
| high = low = false; | |
| } | |
| while( ! low && ! high ){ | |
| q = Bval.quoRemIteration( Sval ); | |
| assert q < 10 : q; // excessively large digit | |
| Mval = Mval.multBy10(); //Mval = Mval.mult( 10 ); | |
| low = (Bval.cmp( Mval ) < 0); | |
| high = tenSval.addAndCmp(Bval,Mval)<=0; | |
| digits[ndigit++] = (char)('0' + q); | |
| } | |
| if ( high && low ){ | |
| Bval = Bval.leftShift(1); | |
| lowDigitDifference = Bval.cmp(tenSval); | |
| } else { | |
| lowDigitDifference = 0L; // this here only for flow analysis! | |
| } | |
| exactDecimalConversion = (Bval.cmp( FDBigInteger.ZERO ) == 0); | |
| } | |
| this.decExponent = decExp+1; | |
| this.firstDigitIndex = 0; | |
| this.nDigits = ndigit; | |
| // | |
| // Last digit gets rounded based on stopping condition. | |
| // | |
| if ( high ){ | |
| if ( low ){ | |
| if ( lowDigitDifference == 0L ){ | |
| // it's a tie! | |
| // choose based on which digits we like. | |
| if ( (digits[firstDigitIndex+nDigits-1]&1) != 0 ) { | |
| roundup(); | |
| } | |
| } else if ( lowDigitDifference > 0 ){ | |
| roundup(); | |
| } | |
| } else { | |
| roundup(); | |
| } | |
| } | |
| } | |
| // add one to the least significant digit. | |
| // in the unlikely event there is a carry out, deal with it. | |
| // assert that this will only happen where there | |
| // is only one digit, e.g. (float)1e-44 seems to do it. | |
| // | |
| private void roundup() { | |
| int i = (firstDigitIndex + nDigits - 1); | |
| int q = digits[i]; | |
| if (q == '9') { | |
| while (q == '9' && i > firstDigitIndex) { | |
| digits[i] = '0'; | |
| q = digits[--i]; | |
| } | |
| if (q == '9') { | |
| // carryout! High-order 1, rest 0s, larger exp. | |
| decExponent += 1; | |
| digits[firstDigitIndex] = '1'; | |
| return; | |
| } | |
| // else fall through. | |
| } | |
| digits[i] = (char) (q + 1); | |
| decimalDigitsRoundedUp = true; | |
| } | |
| /** | |
| * Estimate decimal exponent. (If it is small-ish, | |
| * we could double-check.) | |
| * | |
| * First, scale the mantissa bits such that 1 <= d2 < 2. | |
| * We are then going to estimate | |
| * log10(d2) ~=~ (d2-1.5)/1.5 + log(1.5) | |
| * and so we can estimate | |
| * log10(d) ~=~ log10(d2) + binExp * log10(2) | |
| * take the floor and call it decExp. | |
| */ | |
| static int estimateDecExp(long fractBits, int binExp) { | |
| double d2 = Double.longBitsToDouble( EXP_ONE | ( fractBits & DoubleConsts.SIGNIF_BIT_MASK ) ); | |
| double d = (d2-1.5D)*0.289529654D + 0.176091259 + (double)binExp * 0.301029995663981; | |
| long dBits = Double.doubleToRawLongBits(d); //can't be NaN here so use raw | |
| int exponent = (int)((dBits & DoubleConsts.EXP_BIT_MASK) >> EXP_SHIFT) - DoubleConsts.EXP_BIAS; | |
| boolean isNegative = (dBits & DoubleConsts.SIGN_BIT_MASK) != 0; // discover sign | |
| if(exponent>=0 && exponent<52) { // hot path | |
| long mask = DoubleConsts.SIGNIF_BIT_MASK >> exponent; | |
| int r = (int)(( (dBits&DoubleConsts.SIGNIF_BIT_MASK) | FRACT_HOB )>>(EXP_SHIFT-exponent)); | |
| return isNegative ? (((mask & dBits) == 0L ) ? -r : -r-1 ) : r; | |
| } else if (exponent < 0) { | |
| return (((dBits&~DoubleConsts.SIGN_BIT_MASK) == 0) ? 0 : | |
| ( (isNegative) ? -1 : 0) ); | |
| } else { //if (exponent >= 52) | |
| return (int)d; | |
| } | |
| } | |
| private static int insignificantDigits(long insignificant) { | |
| int i; | |
| for ( i = 0; insignificant >= 10L; i++ ) { | |
| insignificant /= 10L; | |
| } | |
| return i; | |
| } | |
| /** | |
| * Calculates | |
| * <pre> | |
| * insignificantDigitsForPow2(v) == insignificantDigits(1L<<v) | |
| * </pre> | |
| */ | |
| private static int insignificantDigitsForPow2(int p2) { | |
| if (p2 > 1 && p2 < insignificantDigitsNumber.length) { | |
| return insignificantDigitsNumber[p2]; | |
| } | |
| return 0; | |
| } | |
| /** | |
| * If insignificant==(1L << ixd) | |
| * i = insignificantDigitsNumber[idx] is the same as: | |
| * int i; | |
| * for ( i = 0; insignificant >= 10L; i++ ) | |
| * insignificant /= 10L; | |
| */ | |
| private static final int[] insignificantDigitsNumber = { | |
| 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, | |
| 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, | |
| 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 11, 11, 11, | |
| 12, 12, 12, 12, 13, 13, 13, 14, 14, 14, | |
| 15, 15, 15, 15, 16, 16, 16, 17, 17, 17, | |
| 18, 18, 18, 19 | |
| }; | |
| // approximately ceil( log2( long5pow[i] ) ) | |
| private static final int[] N_5_BITS = { | |
| 0, | |
| 3, | |
| 5, | |
| 7, | |
| 10, | |
| 12, | |
| 14, | |
| 17, | |
| 19, | |
| 21, | |
| 24, | |
| 26, | |
| 28, | |
| 31, | |
| 33, | |
| 35, | |
| 38, | |
| 40, | |
| 42, | |
| 45, | |
| 47, | |
| 49, | |
| 52, | |
| 54, | |
| 56, | |
| 59, | |
| 61, | |
| }; | |
| private int getChars(char[] result) { | |
| assert nDigits <= 19 : nDigits; // generous bound on size of nDigits | |
| int i = 0; | |
| if (isNegative) { | |
| result[0] = '-'; | |
| i = 1; | |
| } | |
| if (decExponent > 0 && decExponent < 8) { | |
| // print digits.digits. | |
| int charLength = Math.min(nDigits, decExponent); | |
| System.arraycopy(digits, firstDigitIndex, result, i, charLength); | |
| i += charLength; | |
| if (charLength < decExponent) { | |
| charLength = decExponent - charLength; | |
| Arrays.fill(result,i,i+charLength,'0'); | |
| i += charLength; | |
| result[i++] = '.'; | |
| result[i++] = '0'; | |
| } else { | |
| result[i++] = '.'; | |
| if (charLength < nDigits) { | |
| int t = nDigits - charLength; | |
| System.arraycopy(digits, firstDigitIndex+charLength, result, i, t); | |
| i += t; | |
| } else { | |
| result[i++] = '0'; | |
| } | |
| } | |
| } else if (decExponent <= 0 && decExponent > -3) { | |
| result[i++] = '0'; | |
| result[i++] = '.'; | |
| if (decExponent != 0) { | |
| Arrays.fill(result, i, i-decExponent, '0'); | |
| i -= decExponent; | |
| } | |
| System.arraycopy(digits, firstDigitIndex, result, i, nDigits); | |
| i += nDigits; | |
| } else { | |
| result[i++] = digits[firstDigitIndex]; | |
| result[i++] = '.'; | |
| if (nDigits > 1) { | |
| System.arraycopy(digits, firstDigitIndex+1, result, i, nDigits - 1); | |
| i += nDigits - 1; | |
| } else { | |
| result[i++] = '0'; | |
| } | |
| result[i++] = 'E'; | |
| int e; | |
| if (decExponent <= 0) { | |
| result[i++] = '-'; | |
| e = -decExponent + 1; | |
| } else { | |
| e = decExponent - 1; | |
| } | |
| // decExponent has 1, 2, or 3, digits | |
| if (e <= 9) { | |
| result[i++] = (char) (e + '0'); | |
| } else if (e <= 99) { | |
| result[i++] = (char) (e / 10 + '0'); | |
| result[i++] = (char) (e % 10 + '0'); | |
| } else { | |
| result[i++] = (char) (e / 100 + '0'); | |
| e %= 100; | |
| result[i++] = (char) (e / 10 + '0'); | |
| result[i++] = (char) (e % 10 + '0'); | |
| } | |
| } | |
| return i; | |
| } | |
| } | |
| private static final ThreadLocal<BinaryToASCIIBuffer> threadLocalBinaryToASCIIBuffer = | |
| new ThreadLocal<BinaryToASCIIBuffer>() { | |
| @Override | |
| protected BinaryToASCIIBuffer initialValue() { | |
| return new BinaryToASCIIBuffer(); | |
| } | |
| }; | |
| private static BinaryToASCIIBuffer getBinaryToASCIIBuffer() { | |
| return threadLocalBinaryToASCIIBuffer.get(); | |
| } | |
| /** | |
| * A converter which can process an ASCII <code>String</code> representation | |
| * of a single or double precision floating point value into a | |
| * <code>float</code> or a <code>double</code>. | |
| */ | |
| interface ASCIIToBinaryConverter { | |
| double doubleValue(); | |
| float floatValue(); | |
| } | |
| /** | |
| * A <code>ASCIIToBinaryConverter</code> container for a <code>double</code>. | |
| */ | |
| static class PreparedASCIIToBinaryBuffer implements ASCIIToBinaryConverter { | |
| private final double doubleVal; | |
| private final float floatVal; | |
| public PreparedASCIIToBinaryBuffer(double doubleVal, float floatVal) { | |
| this.doubleVal = doubleVal; | |
| this.floatVal = floatVal; | |
| } | |
| @Override | |
| public double doubleValue() { | |
| return doubleVal; | |
| } | |
| @Override | |
| public float floatValue() { | |
| return floatVal; | |
| } | |
| } | |
| static final ASCIIToBinaryConverter A2BC_POSITIVE_INFINITY = new PreparedASCIIToBinaryBuffer(Double.POSITIVE_INFINITY, Float.POSITIVE_INFINITY); | |
| static final ASCIIToBinaryConverter A2BC_NEGATIVE_INFINITY = new PreparedASCIIToBinaryBuffer(Double.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY); | |
| static final ASCIIToBinaryConverter A2BC_NOT_A_NUMBER = new PreparedASCIIToBinaryBuffer(Double.NaN, Float.NaN); | |
| static final ASCIIToBinaryConverter A2BC_POSITIVE_ZERO = new PreparedASCIIToBinaryBuffer(0.0d, 0.0f); | |
| static final ASCIIToBinaryConverter A2BC_NEGATIVE_ZERO = new PreparedASCIIToBinaryBuffer(-0.0d, -0.0f); | |
| /** | |
| * A buffered implementation of <code>ASCIIToBinaryConverter</code>. | |
| */ | |
| static class ASCIIToBinaryBuffer implements ASCIIToBinaryConverter { | |
| boolean isNegative; | |
| int decExponent; | |
| byte[] digits; | |
| int nDigits; | |
| ASCIIToBinaryBuffer( boolean negSign, int decExponent, byte[] digits, int n) | |
| { | |
| this.isNegative = negSign; | |
| this.decExponent = decExponent; | |
| this.digits = digits; | |
| this.nDigits = n; | |
| } | |
| /** | |
| * Takes a FloatingDecimal, which we presumably just scanned in, | |
| * and finds out what its value is, as a double. | |
| * | |
| * AS A SIDE EFFECT, SET roundDir TO INDICATE PREFERRED | |
| * ROUNDING DIRECTION in case the result is really destined | |
| * for a single-precision float. | |
| */ | |
| @Override | |
| public double doubleValue() { | |
| int kDigits = Math.min(nDigits, MAX_DECIMAL_DIGITS + 1); | |
| // | |
| // convert the lead kDigits to a long integer. | |
| // | |
| // (special performance hack: start to do it using int) | |
| int iValue = (int) digits[0] - (int) '0'; | |
| int iDigits = Math.min(kDigits, INT_DECIMAL_DIGITS); | |
| for (int i = 1; i < iDigits; i++) { | |
| iValue = iValue * 10 + (int) digits[i] - (int) '0'; | |
| } | |
| long lValue = (long) iValue; | |
| for (int i = iDigits; i < kDigits; i++) { | |
| lValue = lValue * 10L + (long) ((int) digits[i] - (int) '0'); | |
| } | |
| double dValue = (double) lValue; | |
| int exp = decExponent - kDigits; | |
| // | |
| // lValue now contains a long integer with the value of | |
| // the first kDigits digits of the number. | |
| // dValue contains the (double) of the same. | |
| // | |
| if (nDigits <= MAX_DECIMAL_DIGITS) { | |
| // | |
| // possibly an easy case. | |
| // We know that the digits can be represented | |
| // exactly. And if the exponent isn't too outrageous, | |
| // the whole thing can be done with one operation, | |
| // thus one rounding error. | |
| // Note that all our constructors trim all leading and | |
| // trailing zeros, so simple values (including zero) | |
| // will always end up here | |
| // | |
| if (exp == 0 || dValue == 0.0) { | |
| return (isNegative) ? -dValue : dValue; // small floating integer | |
| } | |
| else if (exp >= 0) { | |
| if (exp <= MAX_SMALL_TEN) { | |
| // | |
| // Can get the answer with one operation, | |
| // thus one roundoff. | |
| // | |
| double rValue = dValue * SMALL_10_POW[exp]; | |
| return (isNegative) ? -rValue : rValue; | |
| } | |
| int slop = MAX_DECIMAL_DIGITS - kDigits; | |
| if (exp <= MAX_SMALL_TEN + slop) { | |
| // | |
| // We can multiply dValue by 10^(slop) | |
| // and it is still "small" and exact. | |
| // Then we can multiply by 10^(exp-slop) | |
| // with one rounding. | |
| // | |
| dValue *= SMALL_10_POW[slop]; | |
| double rValue = dValue * SMALL_10_POW[exp - slop]; | |
| return (isNegative) ? -rValue : rValue; | |
| } | |
| // | |
| // Else we have a hard case with a positive exp. | |
| // | |
| } else { | |
| if (exp >= -MAX_SMALL_TEN) { | |
| // | |
| // Can get the answer in one division. | |
| // | |
| double rValue = dValue / SMALL_10_POW[-exp]; | |
| return (isNegative) ? -rValue : rValue; | |
| } | |
| // | |
| // Else we have a hard case with a negative exp. | |
| // | |
| } | |
| } | |
| // | |
| // Harder cases: | |
| // The sum of digits plus exponent is greater than | |
| // what we think we can do with one error. | |
| // | |
| // Start by approximating the right answer by, | |
| // naively, scaling by powers of 10. | |
| // | |
| if (exp > 0) { | |
| if (decExponent > MAX_DECIMAL_EXPONENT + 1) { | |
| // | |
| // Lets face it. This is going to be | |
| // Infinity. Cut to the chase. | |
| // | |
| return (isNegative) ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY; | |
| } | |
| if ((exp & 15) != 0) { | |
| dValue *= SMALL_10_POW[exp & 15]; | |
| } | |
| if ((exp >>= 4) != 0) { | |
| int j; | |
| for (j = 0; exp > 1; j++, exp >>= 1) { | |
| if ((exp & 1) != 0) { | |
| dValue *= BIG_10_POW[j]; | |
| } | |
| } | |
| // | |
| // The reason for the weird exp > 1 condition | |
| // in the above loop was so that the last multiply | |
| // would get unrolled. We handle it here. | |
| // It could overflow. | |
| // | |
| double t = dValue * BIG_10_POW[j]; | |
| if (Double.isInfinite(t)) { | |
| // | |
| // It did overflow. | |
| // Look more closely at the result. | |
| // If the exponent is just one too large, | |
| // then use the maximum finite as our estimate | |
| // value. Else call the result infinity | |
| // and punt it. | |
| // ( I presume this could happen because | |
| // rounding forces the result here to be | |
| // an ULP or two larger than | |
| // Double.MAX_VALUE ). | |
| // | |
| t = dValue / 2.0; | |
| t *= BIG_10_POW[j]; | |
| if (Double.isInfinite(t)) { | |
| return (isNegative) ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY; | |
| } | |
| t = Double.MAX_VALUE; | |
| } | |
| dValue = t; | |
| } | |
| } else if (exp < 0) { | |
| exp = -exp; | |
| if (decExponent < MIN_DECIMAL_EXPONENT - 1) { | |
| // | |
| // Lets face it. This is going to be | |
| // zero. Cut to the chase. | |
| // | |
| return (isNegative) ? -0.0 : 0.0; | |
| } | |
| if ((exp & 15) != 0) { | |
| dValue /= SMALL_10_POW[exp & 15]; | |
| } | |
| if ((exp >>= 4) != 0) { | |
| int j; | |
| for (j = 0; exp > 1; j++, exp >>= 1) { | |
| if ((exp & 1) != 0) { | |
| dValue *= TINY_10_POW[j]; | |
| } | |
| } | |
| // | |
| // The reason for the weird exp > 1 condition | |
| // in the above loop was so that the last multiply | |
| // would get unrolled. We handle it here. | |
| // It could underflow. | |
| // | |
| double t = dValue * TINY_10_POW[j]; | |
| if (t == 0.0) { | |
| // | |
| // It did underflow. | |
| // Look more closely at the result. | |
| // If the exponent is just one too small, | |
| // then use the minimum finite as our estimate | |
| // value. Else call the result 0.0 | |
| // and punt it. | |
| // ( I presume this could happen because | |
| // rounding forces the result here to be | |
| // an ULP or two less than | |
| // Double.MIN_VALUE ). | |
| // | |
| t = dValue * 2.0; | |
| t *= TINY_10_POW[j]; | |
| if (t == 0.0) { | |
| return (isNegative) ? -0.0 : 0.0; | |
| } | |
| t = Double.MIN_VALUE; | |
| } | |
| dValue = t; | |
| } | |
| } | |
| // | |
| // dValue is now approximately the result. | |
| // The hard part is adjusting it, by comparison | |
| // with FDBigInteger arithmetic. | |
| // Formulate the EXACT big-number result as | |
| // bigD0 * 10^exp | |
| // | |
| if (nDigits > MAX_NDIGITS) { | |
| nDigits = MAX_NDIGITS + 1; | |
| digits[MAX_NDIGITS] = '1'; | |
| } | |
| FDBigInteger bigD0 = new FDBigInteger(lValue, digits, kDigits, nDigits); | |
| exp = decExponent - nDigits; | |
| long ieeeBits = Double.doubleToRawLongBits(dValue); // IEEE-754 bits of double candidate | |
| final int B5 = Math.max(0, -exp); // powers of 5 in bigB, value is not modified inside correctionLoop | |
| final int D5 = Math.max(0, exp); // powers of 5 in bigD, value is not modified inside correctionLoop | |
| bigD0 = bigD0.multByPow52(D5, 0); | |
| bigD0.makeImmutable(); // prevent bigD0 modification inside correctionLoop | |
| FDBigInteger bigD = null; | |
| int prevD2 = 0; | |
| correctionLoop: | |
| while (true) { | |
| // here ieeeBits can't be NaN, Infinity or zero | |
| int binexp = (int) (ieeeBits >>> EXP_SHIFT); | |
| long bigBbits = ieeeBits & DoubleConsts.SIGNIF_BIT_MASK; | |
| if (binexp > 0) { | |
| bigBbits |= FRACT_HOB; | |
| } else { // Normalize denormalized numbers. | |
| assert bigBbits != 0L : bigBbits; // doubleToBigInt(0.0) | |
| int leadingZeros = Long.numberOfLeadingZeros(bigBbits); | |
| int shift = leadingZeros - (63 - EXP_SHIFT); | |
| bigBbits <<= shift; | |
| binexp = 1 - shift; | |
| } | |
| binexp -= DoubleConsts.EXP_BIAS; | |
| int lowOrderZeros = Long.numberOfTrailingZeros(bigBbits); | |
| bigBbits >>>= lowOrderZeros; | |
| final int bigIntExp = binexp - EXP_SHIFT + lowOrderZeros; | |
| final int bigIntNBits = EXP_SHIFT + 1 - lowOrderZeros; | |
| // | |
| // Scale bigD, bigB appropriately for | |
| // big-integer operations. | |
| // Naively, we multiply by powers of ten | |
| // and powers of two. What we actually do | |
| // is keep track of the powers of 5 and | |
| // powers of 2 we would use, then factor out | |
| // common divisors before doing the work. | |
| // | |
| int B2 = B5; // powers of 2 in bigB | |
| int D2 = D5; // powers of 2 in bigD | |
| int Ulp2; // powers of 2 in halfUlp. | |
| if (bigIntExp >= 0) { | |
| B2 += bigIntExp; | |
| } else { | |
| D2 -= bigIntExp; | |
| } | |
| Ulp2 = B2; | |
| // shift bigB and bigD left by a number s. t. | |
| // halfUlp is still an integer. | |
| int hulpbias; | |
| if (binexp <= -DoubleConsts.EXP_BIAS) { | |
| // This is going to be a denormalized number | |
| // (if not actually zero). | |
| // half an ULP is at 2^-(DoubleConsts.EXP_BIAS+EXP_SHIFT+1) | |
| hulpbias = binexp + lowOrderZeros + DoubleConsts.EXP_BIAS; | |
| } else { | |
| hulpbias = 1 + lowOrderZeros; | |
| } | |
| B2 += hulpbias; | |
| D2 += hulpbias; | |
| // if there are common factors of 2, we might just as well | |
| // factor them out, as they add nothing useful. | |
| int common2 = Math.min(B2, Math.min(D2, Ulp2)); | |
| B2 -= common2; | |
| D2 -= common2; | |
| Ulp2 -= common2; | |
| // do multiplications by powers of 5 and 2 | |
| FDBigInteger bigB = FDBigInteger.valueOfMulPow52(bigBbits, B5, B2); | |
| if (bigD == null || prevD2 != D2) { | |
| bigD = bigD0.leftShift(D2); | |
| prevD2 = D2; | |
| } | |
| // | |
| // to recap: | |
| // bigB is the scaled-big-int version of our floating-point | |
| // candidate. | |
| // bigD is the scaled-big-int version of the exact value | |
| // as we understand it. | |
| // halfUlp is 1/2 an ulp of bigB, except for special cases | |
| // of exact powers of 2 | |
| // | |
| // the plan is to compare bigB with bigD, and if the difference | |
| // is less than halfUlp, then we're satisfied. Otherwise, | |
| // use the ratio of difference to halfUlp to calculate a fudge | |
| // factor to add to the floating value, then go 'round again. | |
| // | |
| FDBigInteger diff; | |
| int cmpResult; | |
| boolean overvalue; | |
| if ((cmpResult = bigB.cmp(bigD)) > 0) { | |
| overvalue = true; // our candidate is too big. | |
| diff = bigB.leftInplaceSub(bigD); // bigB is not user further - reuse | |
| if ((bigIntNBits == 1) && (bigIntExp > -DoubleConsts.EXP_BIAS + 1)) { | |
| // candidate is a normalized exact power of 2 and | |
| // is too big (larger than Double.MIN_NORMAL). We will be subtracting. | |
| // For our purposes, ulp is the ulp of the | |
| // next smaller range. | |
| Ulp2 -= 1; | |
| if (Ulp2 < 0) { | |
| // rats. Cannot de-scale ulp this far. | |
| // must scale diff in other direction. | |
| Ulp2 = 0; | |
| diff = diff.leftShift(1); | |
| } | |
| } | |
| } else if (cmpResult < 0) { | |
| overvalue = false; // our candidate is too small. | |
| diff = bigD.rightInplaceSub(bigB); // bigB is not user further - reuse | |
| } else { | |
| // the candidate is exactly right! | |
| // this happens with surprising frequency | |
| break correctionLoop; | |
| } | |
| cmpResult = diff.cmpPow52(B5, Ulp2); | |
| if ((cmpResult) < 0) { | |
| // difference is small. | |
| // this is close enough | |
| break correctionLoop; | |
| } else if (cmpResult == 0) { | |
| // difference is exactly half an ULP | |
| // round to some other value maybe, then finish | |
| if ((ieeeBits & 1) != 0) { // half ties to even | |
| ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp | |
| } | |
| break correctionLoop; | |
| } else { | |
| // difference is non-trivial. | |
| // could scale addend by ratio of difference to | |
| // halfUlp here, if we bothered to compute that difference. | |
| // Most of the time ( I hope ) it is about 1 anyway. | |
| ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp | |
| if (ieeeBits == 0 || ieeeBits == DoubleConsts.EXP_BIT_MASK) { // 0.0 or Double.POSITIVE_INFINITY | |
| break correctionLoop; // oops. Fell off end of range. | |
| } | |
| continue; // try again. | |
| } | |
| } | |
| if (isNegative) { | |
| ieeeBits |= DoubleConsts.SIGN_BIT_MASK; | |
| } | |
| return Double.longBitsToDouble(ieeeBits); | |
| } | |
| /** | |
| * Takes a FloatingDecimal, which we presumably just scanned in, | |
| * and finds out what its value is, as a float. | |
| * This is distinct from doubleValue() to avoid the extremely | |
| * unlikely case of a double rounding error, wherein the conversion | |
| * to double has one rounding error, and the conversion of that double | |
| * to a float has another rounding error, IN THE WRONG DIRECTION, | |
| * ( because of the preference to a zero low-order bit ). | |
| */ | |
| @Override | |
| public float floatValue() { | |
| int kDigits = Math.min(nDigits, SINGLE_MAX_DECIMAL_DIGITS + 1); | |
| // | |
| // convert the lead kDigits to an integer. | |
| // | |
| int iValue = (int) digits[0] - (int) '0'; | |
| for (int i = 1; i < kDigits; i++) { | |
| iValue = iValue * 10 + (int) digits[i] - (int) '0'; | |
| } | |
| float fValue = (float) iValue; | |
| int exp = decExponent - kDigits; | |
| // | |
| // iValue now contains an integer with the value of | |
| // the first kDigits digits of the number. | |
| // fValue contains the (float) of the same. | |
| // | |
| if (nDigits <= SINGLE_MAX_DECIMAL_DIGITS) { | |
| // | |
| // possibly an easy case. | |
| // We know that the digits can be represented | |
| // exactly. And if the exponent isn't too outrageous, | |
| // the whole thing can be done with one operation, | |
| // thus one rounding error. | |
| // Note that all our constructors trim all leading and | |
| // trailing zeros, so simple values (including zero) | |
| // will always end up here. | |
| // | |
| if (exp == 0 || fValue == 0.0f) { | |
| return (isNegative) ? -fValue : fValue; // small floating integer | |
| } else if (exp >= 0) { | |
| if (exp <= SINGLE_MAX_SMALL_TEN) { | |
| // | |
| // Can get the answer with one operation, | |
| // thus one roundoff. | |
| // | |
| fValue *= SINGLE_SMALL_10_POW[exp]; | |
| return (isNegative) ? -fValue : fValue; | |
| } | |
| int slop = SINGLE_MAX_DECIMAL_DIGITS - kDigits; | |
| if (exp <= SINGLE_MAX_SMALL_TEN + slop) { | |
| // | |
| // We can multiply fValue by 10^(slop) | |
| // and it is still "small" and exact. | |
| // Then we can multiply by 10^(exp-slop) | |
| // with one rounding. | |
| // | |
| fValue *= SINGLE_SMALL_10_POW[slop]; | |
| fValue *= SINGLE_SMALL_10_POW[exp - slop]; | |
| return (isNegative) ? -fValue : fValue; | |
| } | |
| // | |
| // Else we have a hard case with a positive exp. | |
| // | |
| } else { | |
| if (exp >= -SINGLE_MAX_SMALL_TEN) { | |
| // | |
| // Can get the answer in one division. | |
| // | |
| fValue /= SINGLE_SMALL_10_POW[-exp]; | |
| return (isNegative) ? -fValue : fValue; | |
| } | |
| // | |
| // Else we have a hard case with a negative exp. | |
| // | |
| } | |
| } else if ((decExponent >= nDigits) && (nDigits + decExponent <= MAX_DECIMAL_DIGITS)) { | |
| // | |
| // In double-precision, this is an exact floating integer. | |
| // So we can compute to double, then shorten to float | |
| // with one round, and get the right answer. | |
| // | |
| // First, finish accumulating digits. | |
| // Then convert that integer to a double, multiply | |
| // by the appropriate power of ten, and convert to float. | |
| // | |
| long lValue = (long) iValue; | |
| for (int i = kDigits; i < nDigits; i++) { | |
| lValue = lValue * 10L + (long) ((int) digits[i] - (int) '0'); | |
| } | |
| double dValue = (double) lValue; | |
| exp = decExponent - nDigits; | |
| dValue *= SMALL_10_POW[exp]; | |
| fValue = (float) dValue; | |
| return (isNegative) ? -fValue : fValue; | |
| } | |
| // | |
| // Harder cases: | |
| // The sum of digits plus exponent is greater than | |
| // what we think we can do with one error. | |
| // | |
| // Start by approximating the right answer by, | |
| // naively, scaling by powers of 10. | |
| // Scaling uses doubles to avoid overflow/underflow. | |
| // | |
| double dValue = fValue; | |
| if (exp > 0) { | |
| if (decExponent > SINGLE_MAX_DECIMAL_EXPONENT + 1) { | |
| // | |
| // Lets face it. This is going to be | |
| // Infinity. Cut to the chase. | |
| // | |
| return (isNegative) ? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY; | |
| } | |
| if ((exp & 15) != 0) { | |
| dValue *= SMALL_10_POW[exp & 15]; | |
| } | |
| if ((exp >>= 4) != 0) { | |
| int j; | |
| for (j = 0; exp > 0; j++, exp >>= 1) { | |
| if ((exp & 1) != 0) { | |
| dValue *= BIG_10_POW[j]; | |
| } | |
| } | |
| } | |
| } else if (exp < 0) { | |
| exp = -exp; | |
| if (decExponent < SINGLE_MIN_DECIMAL_EXPONENT - 1) { | |
| // | |
| // Lets face it. This is going to be | |
| // zero. Cut to the chase. | |
| // | |
| return (isNegative) ? -0.0f : 0.0f; | |
| } | |
| if ((exp & 15) != 0) { | |
| dValue /= SMALL_10_POW[exp & 15]; | |
| } | |
| if ((exp >>= 4) != 0) { | |
| int j; | |
| for (j = 0; exp > 0; j++, exp >>= 1) { | |
| if ((exp & 1) != 0) { | |
| dValue *= TINY_10_POW[j]; | |
| } | |
| } | |
| } | |
| } | |
| fValue = Math.clamp((float) dValue, Float.MIN_VALUE, Float.MAX_VALUE); | |
| // | |
| // fValue is now approximately the result. | |
| // The hard part is adjusting it, by comparison | |
| // with FDBigInteger arithmetic. | |
| // Formulate the EXACT big-number result as | |
| // bigD0 * 10^exp | |
| // | |
| if (nDigits > SINGLE_MAX_NDIGITS) { | |
| nDigits = SINGLE_MAX_NDIGITS + 1; | |
| digits[SINGLE_MAX_NDIGITS] = '1'; | |
| } | |
| FDBigInteger bigD0 = new FDBigInteger(iValue, digits, kDigits, nDigits); | |
| exp = decExponent - nDigits; | |
| int ieeeBits = Float.floatToRawIntBits(fValue); // IEEE-754 bits of float candidate | |
| final int B5 = Math.max(0, -exp); // powers of 5 in bigB, value is not modified inside correctionLoop | |
| final int D5 = Math.max(0, exp); // powers of 5 in bigD, value is not modified inside correctionLoop | |
| bigD0 = bigD0.multByPow52(D5, 0); | |
| bigD0.makeImmutable(); // prevent bigD0 modification inside correctionLoop | |
| FDBigInteger bigD = null; | |
| int prevD2 = 0; | |
| correctionLoop: | |
| while (true) { | |
| // here ieeeBits can't be NaN, Infinity or zero | |
| int binexp = ieeeBits >>> SINGLE_EXP_SHIFT; | |
| int bigBbits = ieeeBits & FloatConsts.SIGNIF_BIT_MASK; | |
| if (binexp > 0) { | |
| bigBbits |= SINGLE_FRACT_HOB; | |
| } else { // Normalize denormalized numbers. | |
| assert bigBbits != 0 : bigBbits; // floatToBigInt(0.0) | |
| int leadingZeros = Integer.numberOfLeadingZeros(bigBbits); | |
| int shift = leadingZeros - (31 - SINGLE_EXP_SHIFT); | |
| bigBbits <<= shift; | |
| binexp = 1 - shift; | |
| } | |
| binexp -= FloatConsts.EXP_BIAS; | |
| int lowOrderZeros = Integer.numberOfTrailingZeros(bigBbits); | |
| bigBbits >>>= lowOrderZeros; | |
| final int bigIntExp = binexp - SINGLE_EXP_SHIFT + lowOrderZeros; | |
| final int bigIntNBits = SINGLE_EXP_SHIFT + 1 - lowOrderZeros; | |
| // | |
| // Scale bigD, bigB appropriately for | |
| // big-integer operations. | |
| // Naively, we multiply by powers of ten | |
| // and powers of two. What we actually do | |
| // is keep track of the powers of 5 and | |
| // powers of 2 we would use, then factor out | |
| // common divisors before doing the work. | |
| // | |
| int B2 = B5; // powers of 2 in bigB | |
| int D2 = D5; // powers of 2 in bigD | |
| int Ulp2; // powers of 2 in halfUlp. | |
| if (bigIntExp >= 0) { | |
| B2 += bigIntExp; | |
| } else { | |
| D2 -= bigIntExp; | |
| } | |
| Ulp2 = B2; | |
| // shift bigB and bigD left by a number s. t. | |
| // halfUlp is still an integer. | |
| int hulpbias; | |
| if (binexp <= -FloatConsts.EXP_BIAS) { | |
| // This is going to be a denormalized number | |
| // (if not actually zero). | |
| // half an ULP is at 2^-(FloatConsts.EXP_BIAS+SINGLE_EXP_SHIFT+1) | |
| hulpbias = binexp + lowOrderZeros + FloatConsts.EXP_BIAS; | |
| } else { | |
| hulpbias = 1 + lowOrderZeros; | |
| } | |
| B2 += hulpbias; | |
| D2 += hulpbias; | |
| // if there are common factors of 2, we might just as well | |
| // factor them out, as they add nothing useful. | |
| int common2 = Math.min(B2, Math.min(D2, Ulp2)); | |
| B2 -= common2; | |
| D2 -= common2; | |
| Ulp2 -= common2; | |
| // do multiplications by powers of 5 and 2 | |
| FDBigInteger bigB = FDBigInteger.valueOfMulPow52(bigBbits, B5, B2); | |
| if (bigD == null || prevD2 != D2) { | |
| bigD = bigD0.leftShift(D2); | |
| prevD2 = D2; | |
| } | |
| // | |
| // to recap: | |
| // bigB is the scaled-big-int version of our floating-point | |
| // candidate. | |
| // bigD is the scaled-big-int version of the exact value | |
| // as we understand it. | |
| // halfUlp is 1/2 an ulp of bigB, except for special cases | |
| // of exact powers of 2 | |
| // | |
| // the plan is to compare bigB with bigD, and if the difference | |
| // is less than halfUlp, then we're satisfied. Otherwise, | |
| // use the ratio of difference to halfUlp to calculate a fudge | |
| // factor to add to the floating value, then go 'round again. | |
| // | |
| FDBigInteger diff; | |
| int cmpResult; | |
| boolean overvalue; | |
| if ((cmpResult = bigB.cmp(bigD)) > 0) { | |
| overvalue = true; // our candidate is too big. | |
| diff = bigB.leftInplaceSub(bigD); // bigB is not user further - reuse | |
| if ((bigIntNBits == 1) && (bigIntExp > -FloatConsts.EXP_BIAS + 1)) { | |
| // candidate is a normalized exact power of 2 and | |
| // is too big (larger than Float.MIN_NORMAL). We will be subtracting. | |
| // For our purposes, ulp is the ulp of the | |
| // next smaller range. | |
| Ulp2 -= 1; | |
| if (Ulp2 < 0) { | |
| // rats. Cannot de-scale ulp this far. | |
| // must scale diff in other direction. | |
| Ulp2 = 0; | |
| diff = diff.leftShift(1); | |
| } | |
| } | |
| } else if (cmpResult < 0) { | |
| overvalue = false; // our candidate is too small. | |
| diff = bigD.rightInplaceSub(bigB); // bigB is not user further - reuse | |
| } else { | |
| // the candidate is exactly right! | |
| // this happens with surprising frequency | |
| break correctionLoop; | |
| } | |
| cmpResult = diff.cmpPow52(B5, Ulp2); | |
| if ((cmpResult) < 0) { | |
| // difference is small. | |
| // this is close enough | |
| break correctionLoop; | |
| } else if (cmpResult == 0) { | |
| // difference is exactly half an ULP | |
| // round to some other value maybe, then finish | |
| if ((ieeeBits & 1) != 0) { // half ties to even | |
| ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp | |
| } | |
| break correctionLoop; | |
| } else { | |
| // difference is non-trivial. | |
| // could scale addend by ratio of difference to | |
| // halfUlp here, if we bothered to compute that difference. | |
| // Most of the time ( I hope ) it is about 1 anyway. | |
| ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp | |
| if (ieeeBits == 0 || ieeeBits == FloatConsts.EXP_BIT_MASK) { // 0.0 or Float.POSITIVE_INFINITY | |
| break correctionLoop; // oops. Fell off end of range. | |
| } | |
| continue; // try again. | |
| } | |
| } | |
| if (isNegative) { | |
| ieeeBits |= FloatConsts.SIGN_BIT_MASK; | |
| } | |
| return Float.intBitsToFloat(ieeeBits); | |
| } | |
| /** | |
| * All the positive powers of 10 that can be | |
| * represented exactly in double/float. | |
| */ | |
| private static final double[] SMALL_10_POW = { | |
| 1.0e0, | |
| 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, | |
| 1.0e6, 1.0e7, 1.0e8, 1.0e9, 1.0e10, | |
| 1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15, | |
| 1.0e16, 1.0e17, 1.0e18, 1.0e19, 1.0e20, | |
| 1.0e21, 1.0e22 | |
| }; | |
| private static final float[] SINGLE_SMALL_10_POW = { | |
| 1.0e0f, | |
| 1.0e1f, 1.0e2f, 1.0e3f, 1.0e4f, 1.0e5f, | |
| 1.0e6f, 1.0e7f, 1.0e8f, 1.0e9f, 1.0e10f | |
| }; | |
| private static final double[] BIG_10_POW = { | |
| 1e16, 1e32, 1e64, 1e128, 1e256 }; | |
| private static final double[] TINY_10_POW = { | |
| 1e-16, 1e-32, 1e-64, 1e-128, 1e-256 }; | |
| private static final int MAX_SMALL_TEN = SMALL_10_POW.length-1; | |
| private static final int SINGLE_MAX_SMALL_TEN = SINGLE_SMALL_10_POW.length-1; | |
| } | |
| /** | |
| * Returns a <code>BinaryToASCIIConverter</code> for a <code>double</code>. | |
| * The returned object is a <code>ThreadLocal</code> variable of this class. | |
| * | |
| * @param d The double precision value to convert. | |
| * @return The converter. | |
| */ | |
| public static BinaryToASCIIConverter getBinaryToASCIIConverter(double d) { | |
| return getBinaryToASCIIConverter(d, true); | |
| } | |
| /** | |
| * Returns a <code>BinaryToASCIIConverter</code> for a <code>double</code>. | |
| * The returned object is a <code>ThreadLocal</code> variable of this class. | |
| * | |
| * @param d The double precision value to convert. | |
| * @param isCompatibleFormat | |
| * @return The converter. | |
| */ | |
| static BinaryToASCIIConverter getBinaryToASCIIConverter(double d, boolean isCompatibleFormat) { | |
| long dBits = Double.doubleToRawLongBits(d); | |
| boolean isNegative = (dBits&DoubleConsts.SIGN_BIT_MASK) != 0; // discover sign | |
| long fractBits = dBits & DoubleConsts.SIGNIF_BIT_MASK; | |
| int binExp = (int)( (dBits&DoubleConsts.EXP_BIT_MASK) >> EXP_SHIFT ); | |
| // Discover obvious special cases of NaN and Infinity. | |
| if ( binExp == (int)(DoubleConsts.EXP_BIT_MASK>>EXP_SHIFT) ) { | |
| if ( fractBits == 0L ){ | |
| return isNegative ? B2AC_NEGATIVE_INFINITY : B2AC_POSITIVE_INFINITY; | |
| } else { | |
| return B2AC_NOT_A_NUMBER; | |
| } | |
| } | |
| // Finish unpacking | |
| // Normalize denormalized numbers. | |
| // Insert assumed high-order bit for normalized numbers. | |
| // Subtract exponent bias. | |
| int nSignificantBits; | |
| if ( binExp == 0 ){ | |
| if ( fractBits == 0L ){ | |
| // not a denorm, just a 0! | |
| return isNegative ? B2AC_NEGATIVE_ZERO : B2AC_POSITIVE_ZERO; | |
| } | |
| int leadingZeros = Long.numberOfLeadingZeros(fractBits); | |
| int shift = leadingZeros-(63-EXP_SHIFT); | |
| fractBits <<= shift; | |
| binExp = 1 - shift; | |
| nSignificantBits = 64-leadingZeros; // recall binExp is - shift count. | |
| } else { | |
| fractBits |= FRACT_HOB; | |
| nSignificantBits = EXP_SHIFT+1; | |
| } | |
| binExp -= DoubleConsts.EXP_BIAS; | |
| BinaryToASCIIBuffer buf = getBinaryToASCIIBuffer(); | |
| buf.setSign(isNegative); | |
| // call the routine that actually does all the hard work. | |
| buf.dtoa(binExp, fractBits, nSignificantBits, isCompatibleFormat); | |
| return buf; | |
| } | |
| private static BinaryToASCIIConverter getBinaryToASCIIConverter(float f) { | |
| int fBits = Float.floatToRawIntBits( f ); | |
| boolean isNegative = (fBits&FloatConsts.SIGN_BIT_MASK) != 0; | |
| int fractBits = fBits&FloatConsts.SIGNIF_BIT_MASK; | |
| int binExp = (fBits&FloatConsts.EXP_BIT_MASK) >> SINGLE_EXP_SHIFT; | |
| // Discover obvious special cases of NaN and Infinity. | |
| if ( binExp == (FloatConsts.EXP_BIT_MASK>>SINGLE_EXP_SHIFT) ) { | |
| if ( fractBits == 0L ){ | |
| return isNegative ? B2AC_NEGATIVE_INFINITY : B2AC_POSITIVE_INFINITY; | |
| } else { | |
| return B2AC_NOT_A_NUMBER; | |
| } | |
| } | |
| // Finish unpacking | |
| // Normalize denormalized numbers. | |
| // Insert assumed high-order bit for normalized numbers. | |
| // Subtract exponent bias. | |
| int nSignificantBits; | |
| if ( binExp == 0 ){ | |
| if ( fractBits == 0 ){ | |
| // not a denorm, just a 0! | |
| return isNegative ? B2AC_NEGATIVE_ZERO : B2AC_POSITIVE_ZERO; | |
| } | |
| int leadingZeros = Integer.numberOfLeadingZeros(fractBits); | |
| int shift = leadingZeros-(31-SINGLE_EXP_SHIFT); | |
| fractBits <<= shift; | |
| binExp = 1 - shift; | |
| nSignificantBits = 32 - leadingZeros; // recall binExp is - shift count. | |
| } else { | |
| fractBits |= SINGLE_FRACT_HOB; | |
| nSignificantBits = SINGLE_EXP_SHIFT+1; | |
| } | |
| binExp -= FloatConsts.EXP_BIAS; | |
| BinaryToASCIIBuffer buf = getBinaryToASCIIBuffer(); | |
| buf.setSign(isNegative); | |
| // call the routine that actually does all the hard work. | |
| buf.dtoa(binExp, ((long)fractBits)<<(EXP_SHIFT-SINGLE_EXP_SHIFT), nSignificantBits, true); | |
| return buf; | |
| } | |
| /** | |
| * The input must match the {@link Double#valueOf(String) rules described here}, | |
| * about leading and trailing whitespaces, and the grammar. | |
| * | |
| * @param in the non-null input | |
| * @param ix one of the {@code BINARY_<S>_IX} constants, where {@code <S>} | |
| * is one of 16, 32, 64 | |
| * @return an appropriate binary converter | |
| * @throws NullPointerException if the input is null | |
| * @throws NumberFormatException if the input is malformed | |
| */ | |
| static ASCIIToBinaryConverter readJavaFormatString(String in, int ix) { | |
| /* | |
| * The scanning proper does not allocate any object, | |
| * nor does it perform any costly computation. | |
| * This means that all scanning errors are detected without consuming | |
| * any heap, before actually throwing. | |
| * | |
| * Once scanning is complete, the method determines the length | |
| * of a prefix of the significand that is sufficient for correct | |
| * rounding according to roundTiesToEven. | |
| * The actual value of the prefix length might not be optimal, | |
| * but is always a safe choice. | |
| * | |
| * For hexadecimal input, the prefix is processed by this method directly, | |
| * without allocating objects before creating the returned instance. | |
| * | |
| * For decimal input, the prefix is copied to the returned instance, | |
| * along with the other information needed for the conversion. | |
| * For comparison, the prefix length is at most | |
| * 23 for BINARY_16_IX (Float16, once integrated in java.base) | |
| * 114 for BINARY_32_IX (float) | |
| * 769 for BINARY_64_IX (double) | |
| */ | |
| int len = in.length(); // fail fast on null | |
| /* Skip leading whitespaces. */ | |
| int i = skipWhitespaces(in, 0); // main running index | |
| if (i == len) { | |
| throw new NumberFormatException("empty String"); | |
| } | |
| /* Scan opt significand sign. */ | |
| int ch; // running char | |
| int ssign = ' '; // ' ' iff sign is implicit | |
| if ((ch = in.charAt(i)) == '-' || ch == '+') { // i < len | |
| ssign = ch; | |
| ++i; | |
| } | |
| /* | |
| * In some places the idiom | |
| * (ch | 0b10_0000) == lowercase-letter | |
| * is used as a shortcut for | |
| * ch == lowercase-letter || ch == that-same-letter-as-uppercase | |
| * | |
| * Determine whether we are facing a symbolic value or hex notation. | |
| */ | |
| boolean isDec = true; // decimal input until proven to the contrary | |
| if (i < len) { | |
| ch = in.charAt(i); | |
| if (ch == 'I') { | |
| scanSymbolic(in, i, "Infinity"); | |
| return ssign != '-' ? A2BC_POSITIVE_INFINITY : A2BC_NEGATIVE_INFINITY; | |
| } | |
| if (ch == 'N') { | |
| scanSymbolic(in, i, "NaN"); | |
| return A2BC_NOT_A_NUMBER; // ignore sign | |
| } | |
| if (ch == '0' && i < len - 1 && (in.charAt(i + 1) | 0b10_0000) == 'x') { | |
| isDec = false; | |
| i += 2; | |
| } | |
| } | |
| int pt = 0; // index after point, 0 iff absent | |
| int start = i; // index of start of the significand, excluding opt sign | |
| /* Skip opt leading zeros, including an opt point. */ | |
| while (i < len && ((ch = in.charAt(i)) == '0' || ch == '.')) { | |
| ++i; | |
| if (ch == '.') { | |
| pt = checkMultiplePoints(pt, i); | |
| } | |
| } | |
| int lz = i; // index after leading group of zeros or point | |
| /* | |
| * Scan all remaining chars of the significand, including an opt point. | |
| * Also locate the index after the end of the trailing group of non-zeros | |
| * inside this range of the input. | |
| */ | |
| int tnz = 0; // index after trailing group of non-zeros, 0 iff absent | |
| while (i < len && (isDigit(ch = in.charAt(i), isDec) || ch == '.')) { | |
| i++; | |
| if (ch == '.') { | |
| pt = checkMultiplePoints(pt, i); | |
| } else if (ch != '0') { | |
| tnz = i; | |
| } | |
| } | |
| check(in, i - start > (pt != 0 ? 1 : 0)); // must have at least one digit | |
| int stop = i; // index after the significand | |
| /* Scan exponent part, optional for dec, mandatory for hex. */ | |
| long ep = 0; // exponent, implicitly 0 | |
| boolean hasExp = false; | |
| if (i < len && ((ch = in.charAt(i) | 0b10_0000) == 'e' && isDec | |
| || ch == 'p' && !isDec)) { | |
| ++i; | |
| /* Scan opt exponent sign. */ | |
| int esign = ' '; // esign == ' ' iff the sign is implicit | |
| if (i < len && ((ch = in.charAt(i)) == '-' || ch == '+')) { | |
| esign = ch; | |
| ++i; | |
| } | |
| /* Scan the exponent digits. Accumulate in ep, clamping at 10^10. */ | |
| while (i < len && isDigit(ch = in.charAt(i), true)) { // ep is decimal | |
| ++i; | |
| ep = appendDecDigit(ep, ch); | |
| } | |
| check(in, i - stop >= 3 // at least 3 chars after significand | |
| || i - stop == 2 && esign == ' '); // 2 chars, one is digit | |
| if (esign == '-') { | |
| ep = -ep; | |
| } | |
| hasExp = true; | |
| } | |
| /* | |
| * |ep| < 10^10, or |ep| = 10^10 when considered "large". | |
| * A "large" ep either generates a zero or an infinity. | |
| */ | |
| check(in, isDec | hasExp); | |
| /* Skip opt [FfDd]? suffix. */ | |
| if (i < len && (((ch = in.charAt(i) | 0b10_0000)) == 'f' || ch == 'd')) { | |
| ++i; | |
| } | |
| /* Skip optional trailing whitespaces, then must be at the end of input. */ | |
| check(in, skipWhitespaces(in, i) == len); | |
| /* By now, the input is syntactically correct. */ | |
| if (tnz == 0) { // all zero digits, so ignore ep and point | |
| return ssign != '-' ? A2BC_POSITIVE_ZERO : A2BC_NEGATIVE_ZERO; | |
| } | |
| /* | |
| * Virtually adjust the point position to be just after | |
| * the last non-zero digit by adjusting the exponent accordingly | |
| * (without modifying the physical pt, as it is used later on). | |
| * | |
| * Determine the count of digits, excluding leading and trailing zeros. | |
| * | |
| * These are the possible situations: | |
| * |lz |tnz |stop | |
| * 00000000123456000000234567000000000 | |
| * | |
| * |pt |lz |tnz |stop | |
| * .00000000123456000000234567000000000 | |
| * | |
| * |pt |lz |tnz |stop | |
| * 00.000000123456000000234567000000000 | |
| * | |
| * |pt=lz |tnz |stop | |
| * 00000000.123456000000234567000000000 | |
| * | |
| * |lz |pt |tnz |stop | |
| * 000000001234.56000000234567000000000 | |
| * | |
| * |lz |pt |tnz |stop | |
| * 0000000012345600.0000234567000000000 | |
| * | |
| * |lz |pt |tnz |stop | |
| * 00000000123456000000.234567000000000 | |
| * | |
| * |lz |pt |tnz |stop | |
| * 0000000012345600000023.4567000000000 | |
| * | |
| * |lz |pt=tnz |stop | |
| * 00000000123456000000234567.000000000 | |
| * | |
| * |lz |tnz |pt |stop | |
| * 0000000012345600000023456700000.0000 | |
| * | |
| * |lz |tnz |pt=stop | |
| * 00000000123456000000234567000000000. | |
| * | |
| * In decimal, moving the point by one position means correcting ep by 1. | |
| * In hexadecimal, it means correcting ep by 4. | |
| */ | |
| long emult = isDec ? 1L : 4L; | |
| int n = tnz - lz; // number of significant digits, 1st approximation | |
| if (pt == 0) { | |
| ep += emult * (stop - tnz); | |
| } else { | |
| ep += emult * (pt - tnz); | |
| if (pt > tnz) { // '.' was counted as a position, adjust ep | |
| ep -= emult; | |
| } else if (lz < pt) { // lz < pt <= tnz | |
| n -= 1; | |
| } | |
| } | |
| /* | |
| * n = number of significant digits (that is, not counting leading nor | |
| * trailing zeros) | |
| * |ep| < 10^11 | |
| * | |
| * The magnitude x of the input meets | |
| * x = f 10^ep (decimal) | |
| * x = f 2^ep (hexadecimal) | |
| * Integer f = <f_1 ... f_n> consists of the n decimal or hexadecimal | |
| * digits found in part [lz, tnz) of the input, and f_1 != 0, f_n != 0. | |
| */ | |
| if (!isDec) { // hexadecimal conversion is performed entirely here | |
| /* | |
| * Rounding the leftmost P bits +1 rounding bit +1 sticky bit | |
| * has the same outcome as rounding all bits. | |
| * In terms of hex digits, we need room for HEX_COUNT of them. | |
| */ | |
| int j = 0; | |
| i = lz; | |
| long c = 0; | |
| int le = Math.min(n, HEX_COUNT[ix]); | |
| while (j < le) { | |
| if ((ch = in.charAt(i++)) != '.') { | |
| ++j; | |
| c = c << 4 | digitFor(ch); | |
| } | |
| } | |
| if (n > le) { | |
| c |= 0b1; // force a sticky bit | |
| ep += 4L * (n - le); | |
| } | |
| int bl = Long.SIZE - Long.numberOfLeadingZeros(c); // bit length | |
| /* | |
| * Let x = c 2^ep, so 2^(ep+bl-1) <= x < 2^(ep+bl) | |
| * When ep + bl < Q_MIN then x certainly rounds to zero. | |
| * When ep + bl - 1 > E_MAX then x surely rounds to infinity. | |
| */ | |
| if (ep < Q_MIN[ix] - bl) { | |
| return buildZero(ix, ssign); | |
| } | |
| if (ep > E_MAX[ix] - bl + 1) { | |
| return buildInfinity(ix, ssign); | |
| } | |
| int q = (int) ep; // narrowing conversion is safe | |
| int shr; // (sh)ift to (r)ight iff shr > 0 | |
| if (q > E_MIN[ix] - bl) { | |
| shr = bl - P[ix]; | |
| q += shr; | |
| } else { | |
| shr = Q_MIN[ix] - q; | |
| q = Q_MIN[ix]; | |
| } | |
| if (shr > 0) { | |
| long thr = 1L << shr; | |
| long tail = (c & thr - 1) << 1; | |
| c >>>= shr; | |
| if (tail > thr || tail == thr && (c & 0b1) != 0) { | |
| c += 1; | |
| if (c >= 1L << P[ix]) { // but in fact it can't be > | |
| c >>>= 1; | |
| q += 1; | |
| } | |
| } | |
| } else { | |
| c <<= -shr; | |
| } | |
| /* For now throw on BINARY_16_IX, until Float16 is integrated in java.base. */ | |
| return switch (ix) { | |
| case BINARY_32_IX -> | |
| new PreparedASCIIToBinaryBuffer(Double.NaN, buildFloat(ssign, q, c)); | |
| case BINARY_64_IX -> | |
| new PreparedASCIIToBinaryBuffer(buildDouble(ssign, q, c), Float.NaN); | |
| default -> throw new AssertionError("unexpected"); | |
| }; | |
| } | |
| /* | |
| * For decimal inputs, we copy an appropriate prefix of the input and | |
| * rely on another method to do the (sometimes intensive) math conversion. | |
| * | |
| * Define e' = n + ep, which leads to | |
| * x = <0 . f_1 ... f_n> 10^e', 10^(e'-1) <= x < 10^e' | |
| * If e' <= EP_MIN then x rounds to zero. | |
| * Similarly, if e' >= EP_MAX then x rounds to infinity. | |
| * (See the comments on the fields for their semantics.) | |
| * We return immediately in these cases. | |
| * Otherwise, e' fits in an int named e. | |
| */ | |
| int e = Math.clamp(ep + n, EP_MIN[ix], EP_MAX[ix]); | |
| if (e == EP_MIN[ix]) { // e' <= E_MIN | |
| return ssign != '-' ? A2BC_POSITIVE_ZERO : A2BC_NEGATIVE_ZERO; | |
| } | |
| if (e == EP_MAX[ix]) { // e' >= E_MAX | |
| return ssign != '-' ? A2BC_POSITIVE_INFINITY : A2BC_NEGATIVE_INFINITY; | |
| } | |
| /* | |
| * For further considerations, x also needs to be seen as | |
| * x = beta 2^q | |
| * with real beta and integer q meeting | |
| * 2^(P-1) <= beta < 2^P and q >= Q_MIN | |
| * 0 < beta < 2^(P-1) and q = Q_MIN | |
| * The (unique) solution is | |
| * q = max(floor(log2(x)) - (P-1), Q_MIN), beta = x 2^(-q) | |
| * It's usually costly to determine q as here. | |
| * However, estimates to q are cheaper and quick to compute. | |
| * | |
| * Indeed, it's a matter of some simple maths to show that, by defining | |
| * ql = max(floor((e-1) log2(10)) - (P-1), Q_MIN) | |
| * qh = max(floor(e log2(10)) - (P-1), Q_MIN) | |
| * then the following hold | |
| * ql <= q <= qh, and qh - ql <= 4 | |
| * Since by now e is relatively small, we can leverage flog2pow10(). | |
| * | |
| * When q >= Q_MIN, consider the interval [ 2^(P-1+q), 2^(P+q) ). | |
| * It contains all floating-point values of the form | |
| * c 2^q, c integer, 2^(P-1) <= c < 2^P (normal values) | |
| * When q = Q_MIN also consider the interval [0, 2^(P-1+q) ) | |
| * which contains all floating-point values of the form | |
| * c 2^q, c integer, 0 <= c < 2^(P-1) (subnormal values and zero) | |
| * For these c values, all numbers of the form | |
| * (c + 1/2) 2^q | |
| * also belong to the intervals. | |
| * These are the boundaries of the rounding intervals and are key for | |
| * correct rounding. | |
| * | |
| * First assume ql > 0, so q > 0. | |
| * All rounding boundaries (c + 1/2) 2^q are integers. | |
| * Hence, to correctly round x, it's enough to retain its integer part, | |
| * +1 non-zero sticky digit iff the fractional part is non-zero. | |
| * (Well, the sticky digit is only needed when the integer part | |
| * coincides with a boundary, but that's hard to detect at this stage. | |
| * Adding the sticky digit is always safe.) | |
| * If n > e we pass the digits <f_1 ... f_e 3> (3 is as good as any other | |
| * non-zero sticky digit) and the exponent e to the conversion routine. | |
| * If n <= e we pass all the digits <f_1 ... f_n> (no sticky digit, | |
| * as the fractional part is empty) and the exponent e to the converter. | |
| * | |
| * Now assume qh <= 0, so q <= 0. | |
| * The boundaries (c + 1/2) 2^q = (2c + 1) 2^(q-1) have a fractional part | |
| * of 1 - q digits: some (or zero) leading zeros, the rightmost is 5. | |
| * A correct rounding needs to retain the integer part of x (if any), | |
| * 1 - q digits of the fractional part, +1 non-zero sticky digit iff | |
| * the rest of the fractional part beyond the 1 - q digits is non-zero. | |
| * (Again, the sticky digit is only needed when the digit in f at the | |
| * same position as the last 5 of the rounding boundary is 5 as well. | |
| * But let's keep it simple for now.) | |
| * However, q is unknown, so use the conservative ql instead. | |
| * More precisely, if n > e + 1 - ql we pass the leftmost e + 1 - ql | |
| * digits of f, sticky 3, and e. | |
| * Otherwise, n <= e + 1 - ql. | |
| * We pass all n digits of f, no sticky digit, and e to the converter. | |
| * | |
| * Otherwise, ql <= 0 < qh, so -4 < q <= 4. | |
| * Again, since q is not known exactly, we proceed as in the previous | |
| * case, with ql as a safe replacement for q. | |
| */ | |
| int ql = Math.max(MathUtils.flog2pow10(e - 1) - (P[ix] - 1), Q_MIN[ix]); | |
| int np = e + Math.max(2 - ql, 1); | |
| byte[] digits = new byte[Math.min(n, np)]; | |
| if (n >= np) { | |
| copyDigits(in, digits, np - 1, lz); | |
| digits[np - 1] = '3'; // append any non-zero sticky digit | |
| } else { | |
| copyDigits(in, digits, n, lz); | |
| } | |
| return new ASCIIToBinaryBuffer(ssign == '-', e, digits, digits.length); | |
| } | |
| private static PreparedASCIIToBinaryBuffer buildZero(int ix, int ssign) { | |
| /* For now throw on BINARY_16_IX, until Float16 is integrated in java.base. */ | |
| return switch (ix) { | |
| case BINARY_32_IX -> | |
| new PreparedASCIIToBinaryBuffer( | |
| Double.NaN, | |
| ssign != '-' ? 0.0f : -0.0f); | |
| case BINARY_64_IX -> | |
| new PreparedASCIIToBinaryBuffer( | |
| ssign != '-' ? 0.0d : -0.0d, | |
| Float.NaN); | |
| default -> throw new AssertionError("unexpected"); | |
| }; | |
| } | |
| private static PreparedASCIIToBinaryBuffer buildInfinity(int ix, int ssign) { | |
| /* For now throw on BINARY_16_IX, until Float16 is integrated in java.base. */ | |
| return switch (ix) { | |
| case BINARY_32_IX -> | |
| new PreparedASCIIToBinaryBuffer( | |
| Double.NaN, | |
| ssign != '-' ? Float.POSITIVE_INFINITY : Float.NEGATIVE_INFINITY); | |
| case BINARY_64_IX -> | |
| new PreparedASCIIToBinaryBuffer( | |
| ssign != '-' ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY, | |
| Float.NaN); | |
| default -> throw new AssertionError("unexpected"); | |
| }; | |
| } | |
| private static double buildDouble(int ssign, int q, long c) { | |
| long be = c < 1L << P[BINARY_64_IX] - 1 | |
| ? 0 | |
| : q + ((DoubleConsts.EXP_BIAS - 1) + P[BINARY_64_IX]); | |
| long bits = (ssign != '-' ? 0L : 1L << Double.SIZE - 1) | |
| | be << P[BINARY_64_IX] - 1 | |
| | c & DoubleConsts.SIGNIF_BIT_MASK; | |
| return Double.longBitsToDouble(bits); | |
| } | |
| private static float buildFloat(int ssign, int q, long c) { | |
| int be = c < 1L << P[BINARY_32_IX] - 1 | |
| ? 0 | |
| : q + ((FloatConsts.EXP_BIAS - 1) + P[BINARY_32_IX]); | |
| int bits = (ssign != '-' ? 0 : 1 << Float.SIZE - 1) | |
| | be << P[BINARY_32_IX] - 1 | |
| | (int) c & FloatConsts.SIGNIF_BIT_MASK; | |
| return Float.intBitsToFloat(bits); | |
| } | |
| private static void copyDigits(String in, byte[] digits, int len, int i) { | |
| int ch; | |
| int j = 0; | |
| while (j < len) { | |
| if ((ch = in.charAt(i++)) != '.') { | |
| digits[j++] = (byte) ch; | |
| } | |
| } | |
| } | |
| /* Arithmetically "appends the dec digit" ch to v >= 0, clamping at 10^10. */ | |
| private static long appendDecDigit(long v, int ch) { | |
| return v < 10_000_000_000L / 10 ? 10 * v + (ch - '0') : 10_000_000_000L; | |
| } | |
| /* Whether ch is a digit char '0-9', 'A-F', or 'a-f', depending on isDec. */ | |
| private static boolean isDigit(int ch, boolean isDec) { | |
| int lch; // lowercase ch | |
| return '0' <= ch && ch <= '9' || | |
| !isDec && 'a' <= (lch = ch | 0b10_0000) && lch <= 'f'; | |
| } | |
| /* Returns the numeric value of ch, assuming it is a hexdigit. */ | |
| private static int digitFor(int ch) { | |
| return ch <= '9' ? ch - '0' : (ch | 0b10_0000) - ('a' - 10); | |
| } | |
| /* | |
| * Starting at i, skips all chars in ['\0', ' ']. | |
| * Returns the index after the whitespaces. | |
| */ | |
| private static int skipWhitespaces(String in, int i) { | |
| int len = in.length(); | |
| for (; i < len && in.charAt(i) <= ' '; ++i); // empty body | |
| return i; | |
| } | |
| /* | |
| * Attempts to scan sub and optional trailing whitespaces, starting at index i. | |
| * The optional whitespaces must be at the end of in. | |
| */ | |
| private static void scanSymbolic(String in, int i, String sub) { | |
| int high = i + sub.length(); // might overflow, checked in next line | |
| check(in, i <= high && high <= in.length() | |
| && in.indexOf(sub, i, high) == i | |
| && skipWhitespaces(in, high) == in.length()); | |
| } | |
| /* | |
| * Returns i if this is the first time the scanner detects a point. | |
| * Throws otherwise. | |
| */ | |
| private static int checkMultiplePoints(int pt, int i) { | |
| if (pt != 0) { | |
| throw new NumberFormatException("multiple points"); | |
| } | |
| return i; | |
| } | |
| private static final int MAX_OUT = 1_000; | |
| private static final String OMITTED = " ... "; | |
| private static final int L_HALF = (MAX_OUT - OMITTED.length()) / 2; | |
| private static final int R_HALF = MAX_OUT - (L_HALF + OMITTED.length()); | |
| private static void check(String in, boolean expected) { | |
| if (!expected) { | |
| int len = in.length(); | |
| if (len > MAX_OUT) { // discard middle chars to achieve a length of MAX_OUT | |
| in = in.substring(0, L_HALF) + OMITTED + in.substring(len - R_HALF); | |
| } | |
| throw new NumberFormatException("For input string: \"" + in + "\""); | |
| } | |
| } | |
| /* | |
| * According to IEEE 754-2019, a finite positive binary floating-point | |
| * of precision P is (uniquely) expressed as | |
| * c 2^q | |
| * where integers c and q meet | |
| * Q_MIN <= q <= Q_MAX | |
| * either 2^(P-1) <= c < 2^P (normal) | |
| * or 0 < c < 2^(P-1) & q = Q_MIN (subnormal) | |
| * c = <d_0 d_1 ... d_(P-1)>, d_i in [0, 2) | |
| * | |
| * Equivalently, the fp value can be (uniquely) expressed as | |
| * m 2^ep | |
| * where integer ep and real f meet | |
| * ep = q + P - 1 | |
| * m = c 2^(1-P) | |
| * Hence, | |
| * E_MIN = Q_MIN + P - 1, E_MAX = Q_MAX + P - 1, | |
| * 1 <= m < 2 (normal) | |
| * m < 1 (subnormal) | |
| * m = <d_0 . d_1 ... d_(P-1)> | |
| * with a (binary) point between d_0 and d_1 | |
| */ | |
| /* | |
| * These constants are used to indicate the IEEE binary floating-point format | |
| * as an index (ix) to some methods and static arrays in this class. | |
| */ | |
| private static final int BINARY_16_IX = 0; | |
| private static final int BINARY_32_IX = 1; | |
| private static final int BINARY_64_IX = 2; | |
| // private static final int BINARY_128_IX = 3; | |
| // private static final int BINARY_256_IX = 4; | |
| /* The precision of the format. */ | |
| @Stable | |
| private static final int[] P = { | |
| 11, 24, 53, // 113, 237, | |
| }; | |
| /* | |
| * EP_MIN = max{e : 10^e <= MIN_VALUE/2}. | |
| * Note that MIN_VALUE/2 is the 0 threshold. | |
| * Less or equal values round to 0 when using roundTiesToEven. | |
| * Equivalently, EP_MIN = floor(log10(2^(Q_MIN-1))). | |
| */ | |
| @Stable | |
| private static final int[] EP_MIN = { | |
| -8, -46, -324, // -4_966, -78_985, | |
| }; | |
| /* | |
| * EP_MAX = min{e : MAX_VALUE + ulp(MAX_VALUE)/2 <= 10^(e-1)}. | |
| * Note that MAX_VALUE + ulp(MAX_VALUE)/2 is the infinity threshold. | |
| * Greater or equal values round to infinity when using roundTiesToEven. | |
| * Equivalently, EP_MAX = ceil(log10((2^P - 1/2) 2^Q_MAX)) + 1. | |
| */ | |
| @Stable | |
| private static final int[] EP_MAX = { | |
| 6, 40, 310, // 4_934, 78_915, | |
| }; | |
| /* Exponent width. */ | |
| @Stable | |
| private static final int[] W = { | |
| (1 << 4 + BINARY_16_IX) - P[BINARY_16_IX], | |
| (1 << 4 + BINARY_32_IX) - P[BINARY_32_IX], | |
| (1 << 4 + BINARY_64_IX) - P[BINARY_64_IX], | |
| // (1 << 4 + BINARY_128_IX) - P[BINARY_128_IX], | |
| // (1 << 4 + BINARY_256_IX) - P[BINARY_256_IX], | |
| }; | |
| /* Maximum exponent in the m 2^e representation. */ | |
| @Stable | |
| private static final int[] E_MAX = { | |
| (1 << W[BINARY_16_IX] - 1) - 1, | |
| (1 << W[BINARY_32_IX] - 1) - 1, | |
| (1 << W[BINARY_64_IX] - 1) - 1, | |
| // (1 << W[BINARY_128_IX] - 1) - 1, | |
| // (1 << W[BINARY_256_IX] - 1) - 1, | |
| }; | |
| /* Minimum exponent in the m 2^e representation. */ | |
| @Stable | |
| private static final int[] E_MIN = { | |
| 1 - E_MAX[BINARY_16_IX], | |
| 1 - E_MAX[BINARY_32_IX], | |
| 1 - E_MAX[BINARY_64_IX], | |
| // 1 - E_MAX[BINARY_128_IX], | |
| // 1 - E_MAX[BINARY_256_IX], | |
| }; | |
| /* Minimum exponent in the c 2^q representation. */ | |
| @Stable | |
| private static final int[] Q_MIN = { | |
| E_MIN[BINARY_16_IX] - (P[BINARY_16_IX] - 1), | |
| E_MIN[BINARY_32_IX] - (P[BINARY_32_IX] - 1), | |
| E_MIN[BINARY_64_IX] - (P[BINARY_64_IX] - 1), | |
| // E_MIN[BINARY_128_IX] - (P[BINARY_128_IX] - 1), | |
| // E_MIN[BINARY_256_IX] - (P[BINARY_256_IX] - 1), | |
| }; | |
| /* | |
| * The most significant P +1 rounding bit +1 sticky bit = P + 2 bits in a | |
| * hexadecimal string need up to HEX_COUNT = floor(P/4) + 2 hex digits. | |
| */ | |
| @Stable | |
| private static final int[] HEX_COUNT = { | |
| P[BINARY_16_IX] / 4 + 2, | |
| P[BINARY_32_IX] / 4 + 2, | |
| P[BINARY_64_IX] / 4 + 2, | |
| // P[BINARY_128_IX] / 4 + 2, | |
| // P[BINARY_256_IX] / 4 + 2, | |
| }; | |
| } |