diff --git a/src/java.base/share/classes/java/text/DigitList.java b/src/java.base/share/classes/java/text/DigitList.java index 41c143178daa3..2895126f93ba5 100644 --- a/src/java.base/share/classes/java/text/DigitList.java +++ b/src/java.base/share/classes/java/text/DigitList.java @@ -41,6 +41,9 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.math.RoundingMode; +import java.nio.charset.StandardCharsets; + +import jdk.internal.access.SharedSecrets; import jdk.internal.math.FloatingDecimal; import jdk.internal.util.ArraysSupport; @@ -103,9 +106,9 @@ final class DigitList implements Cloneable { */ public int decimalAt = 0; public int count = 0; - public char[] digits = new char[MAX_COUNT]; + public byte[] digits = new byte[MAX_COUNT]; - private char[] data; + private byte[] data; private RoundingMode roundingMode = RoundingMode.HALF_EVEN; private boolean isNegative = false; @@ -154,11 +157,11 @@ public void clear () { */ public void append(char digit) { if (count == digits.length) { - char[] data = new char[ArraysSupport.newLength(count, 1, count)]; + byte[] data = new byte[ArraysSupport.newLength(count, 1, count)]; System.arraycopy(digits, 0, data, 0, count); digits = data; } - digits[count++] = digit; + digits[count++] = (byte) digit; } /** @@ -188,7 +191,7 @@ public long getLong() { // Parse as unsigned to handle Long.MIN_VALUE, which is the one NEGATIVE value // we represent. If we tried to just pass the digits off to parseLong, // we'd get a parse failure. - long v = Long.parseUnsignedLong(new String(digits, 0, count)); + long v = Long.parseUnsignedLong(new String(digits, 0, count, StandardCharsets.ISO_8859_1)); if (v < 0) { if (v == Long.MIN_VALUE) { return Long.MIN_VALUE; @@ -209,15 +212,20 @@ public long getLong() { * unlike BigDecimal(""). */ public BigDecimal getBigDecimal() { + int count = this.count; if (count == 0) { return BigDecimal.valueOf(0, -decimalAt); } - if (decimalAt == count) { - return new BigDecimal(digits, 0, count); - } else { - return new BigDecimal(digits, 0, count).scaleByPowerOfTen(decimalAt - count); - } + char[] chars = new char[count]; + SharedSecrets.getJavaLangAccess() + .inflateBytesToChars(digits, 0, chars, 0, count); + BigDecimal value = new BigDecimal(chars, 0, count); + if (decimalAt == count) { + return value; + } else { + return value.scaleByPowerOfTen(decimalAt - count); + } } /** @@ -256,7 +264,7 @@ boolean fitsIntoLong(boolean isPositive, boolean ignoreNegativeZero) { // The number will overflow if it is larger than 9223372036854775807 // or smaller than -9223372036854775808. for (int i=0; i max) return false; if (dig < max) return true; } @@ -317,9 +325,10 @@ void set(boolean isNegative, double source, int maximumDigits, boolean fixedPoin boolean hasBeenRoundedUp = fdConverter.digitsRoundedUp(); boolean valueExactAsDecimal = fdConverter.decimalDigitsExact(); assert !fdConverter.isExceptional(); - String digitsString = fdConverter.toJavaFormatString(); - set(isNegative, digitsString, + byte[] chars = getDataChars(26); + int len = fdConverter.getChars(chars); + set(isNegative, chars, len, hasBeenRoundedUp, valueExactAsDecimal, maximumDigits, fixedPoint); } @@ -331,14 +340,11 @@ void set(boolean isNegative, double source, int maximumDigits, boolean fixedPoin * @param valueExactAsDecimal whether or not collected digits provide * an exact decimal representation of the value. */ - private void set(boolean isNegative, String s, + private void set(boolean isNegative, byte[] source, int len, boolean roundedUp, boolean valueExactAsDecimal, int maximumDigits, boolean fixedPoint) { this.isNegative = isNegative; - int len = s.length(); - char[] source = getDataChars(len); - s.getChars(0, len, source, 0); decimalAt = -1; count = 0; @@ -349,7 +355,7 @@ private void set(boolean isNegative, String s, boolean nonZeroDigitSeen = false; for (int i = 0; i < len; ) { - char c = source[i++]; + byte c = source[i++]; if (c == '.') { decimalAt = count; } else if (c == 'e' || c == 'E') { @@ -633,7 +639,7 @@ void set(boolean isNegative, long source, int maximumDigits) { int left = MAX_COUNT; int right; while (source > 0) { - digits[--left] = (char)('0' + (source % 10)); + digits[--left] = (byte)('0' + (source % 10)); source /= 10; } decimalAt = MAX_COUNT - left; @@ -661,11 +667,15 @@ void set(boolean isNegative, long source, int maximumDigits) { * @param fixedPoint If true, then maximumDigits is the maximum * fractional digits to be converted. If false, total digits. */ + @SuppressWarnings("deprecation") void set(boolean isNegative, BigDecimal source, int maximumDigits, boolean fixedPoint) { String s = source.toString(); extendDigits(s.length()); - set(isNegative, s, + int len = s.length(); + byte[] chars = getDataChars(len); + s.getBytes(0, len, chars, 0); + set(isNegative, chars, len, false, true, maximumDigits, fixedPoint); } @@ -678,12 +688,13 @@ void set(boolean isNegative, BigDecimal source, int maximumDigits, boolean fixed * If maximumDigits is lower than the number of significant digits * in source, the representation will be rounded. Ignored if <= 0. */ + @SuppressWarnings("deprecation") void set(boolean isNegative, BigInteger source, int maximumDigits) { this.isNegative = isNegative; String s = source.toString(); int len = s.length(); extendDigits(len); - s.getChars(0, len, digits, 0); + s.getBytes(0, len, digits, 0); decimalAt = len; int right = len - 1; @@ -734,7 +745,7 @@ public int hashCode() { public Object clone() { try { DigitList other = (DigitList) super.clone(); - char[] newDigits = new char[digits.length]; + byte[] newDigits = new byte[digits.length]; System.arraycopy(digits, 0, newDigits, 0, digits.length); other.digits = newDigits; @@ -749,8 +760,8 @@ public Object clone() { } } - private static int parseInt(char[] str, int offset, int strLen) { - char c; + private static int parseInt(byte[] str, int offset, int strLen) { + byte c; boolean positive = true; if ((c = str[offset]) == '-') { positive = false; @@ -772,25 +783,25 @@ private static int parseInt(char[] str, int offset, int strLen) { } // The digit part of -9223372036854775808L - private static final char[] LONG_MIN_REP = "9223372036854775808".toCharArray(); + private static final byte[] LONG_MIN_REP = "9223372036854775808".getBytes(StandardCharsets.ISO_8859_1); public String toString() { if (isZero()) { return "0"; } - return "0." + new String(digits, 0, count) + "x10^" + decimalAt; + return "0." + new String(digits, 0, count, StandardCharsets.ISO_8859_1) + "x10^" + decimalAt; } private void extendDigits(int len) { if (len > digits.length) { - digits = new char[len]; + digits = new byte[len]; } } - private char[] getDataChars(int length) { + private byte[] getDataChars(int length) { if (data == null || data.length < length) { - data = new char[length]; + data = new byte[length]; } return data; } diff --git a/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java b/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java index 168f76fad8fcc..32399310bd3d5 100644 --- a/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java +++ b/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java @@ -60,44 +60,6 @@ public class FloatingDecimal{ static final int INT_DECIMAL_DIGITS = 9; - /** - * Converts a double precision floating point value to a String. - * - * @param d The double precision value. - * @return The value converted to a String. - */ - public static String toJavaFormatString(double d) { - return getBinaryToASCIIConverter(d).toJavaFormatString(); - } - - /** - * Converts a single precision floating point value to a String. - * - * @param f The single precision value. - * @return The value converted to a String. - */ - public static String toJavaFormatString(float f) { - return getBinaryToASCIIConverter(f).toJavaFormatString(); - } - - /** - * Appends a double precision floating point value to an Appendable. - * @param d The double precision value. - * @param buf The Appendable 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 Appendable. - * @param f The single precision value. - * @param buf The Appendable with the value appended. - */ - public static void appendTo(float f, Appendable buf) { - getBinaryToASCIIConverter(f).appendTo(buf); - } - /** * Converts a String to a double precision floating point value. * @@ -131,7 +93,7 @@ public static float parseFloat(String s) throws NumberFormatException { * @param length Number of digits to use * @return The double-precision value of the conversion */ - public static double parseDoubleSignlessDigits(int decExp, char[] digits, int length) { + public static double parseDoubleSignlessDigits(int decExp, byte[] digits, int length) { return readDoubleSignlessDigits(decExp, digits, length).doubleValue(); } @@ -140,17 +102,7 @@ public static double parseDoubleSignlessDigits(int decExp, char[] digits, int le * values into an ASCII String representation. */ public interface BinaryToASCIIConverter { - /** - * Converts a floating point value into an ASCII String. - * @return The value converted to a String. - */ - String toJavaFormatString(); - - /** - * Appends a floating point value to an Appendable. - * @param buf The Appendable to receive the value. - */ - void appendTo(Appendable buf); + int getChars(byte[] result); /** * Retrieves the decimal exponent most closely corresponding to this value. @@ -209,19 +161,10 @@ public ExceptionalBinaryToASCIIBuffer(String image, boolean 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; - } + @SuppressWarnings("deprecation") + public int getChars(byte[] chars) { + image.getBytes(0, image.length(), chars, 0); + return image.length(); } @Override @@ -261,8 +204,8 @@ public boolean decimalDigitsExact() { 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'}); + private static final BinaryToASCIIConverter B2AC_POSITIVE_ZERO = new BinaryToASCIIBuffer(false, new byte[]{'0'}); + private static final BinaryToASCIIConverter B2AC_NEGATIVE_ZERO = new BinaryToASCIIBuffer(true, new byte[]{'0'}); /** * A buffered implementation of BinaryToASCIIConverter. @@ -272,8 +215,7 @@ static class BinaryToASCIIBuffer implements BinaryToASCIIConverter { private int decExponent; private int firstDigitIndex; private int nDigits; - private final char[] digits; - private final char[] buffer = new char[26]; + private final byte[] digits; // // The fields below provide additional information about the result of @@ -293,13 +235,13 @@ static class BinaryToASCIIBuffer implements BinaryToASCIIConverter { * BinaryToASCIIBuffer may be thread-local and reused */ BinaryToASCIIBuffer(){ - this.digits = new char[20]; + this.digits = new byte[20]; } /** * Creates a specialized value (positive and negative zeros). */ - BinaryToASCIIBuffer(boolean isNegative, char[] digits){ + BinaryToASCIIBuffer(boolean isNegative, byte[] digits){ this.isNegative = isNegative; this.decExponent = 0; this.digits = digits; @@ -307,24 +249,6 @@ static class BinaryToASCIIBuffer implements BinaryToASCIIConverter { 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; @@ -403,12 +327,12 @@ private void developLongDigits( int decExponent, long lvalue, int insignificantD ivalue /= 10; } while ( ivalue != 0){ - digits[digitno--] = (char)(c+'0'); + digits[digitno--] = (byte)(c+'0'); decExponent++; c = ivalue%10; ivalue /= 10; } - digits[digitno] = (char)(c+'0'); + digits[digitno] = (byte)(c+'0'); } else { // same algorithm as above (same bugs, too ) // but using long arithmetic. @@ -420,12 +344,12 @@ private void developLongDigits( int decExponent, long lvalue, int insignificantD lvalue /= 10L; } while ( lvalue != 0L ){ - digits[digitno--] = (char)(c+'0'); + digits[digitno--] = (byte) (c+'0'); decExponent++; c = (int)(lvalue%10L); lvalue /= 10; } - digits[digitno] = (char)(c+'0'); + digits[digitno] = (byte)(c+'0'); } this.decExponent = decExponent+1; this.firstDigitIndex = digitno; @@ -626,7 +550,7 @@ private void dtoa( int binExp, long fractBits, int nSignificantBits, boolean isC // oops. Usually ignore leading zero. decExp--; } else { - digits[ndigit++] = (char)('0' + q); + digits[ndigit++] = (byte)('0' + q); } // // HACK! Java spec sez that we always have at least @@ -654,7 +578,7 @@ private void dtoa( int binExp, long fractBits, int nSignificantBits, boolean isC low = true; high = true; } - digits[ndigit++] = (char)('0' + q); + digits[ndigit++] = (byte)('0' + q); } lowDigitDifference = (b<<1) - tens; exactDecimalConversion = (b == 0); @@ -680,7 +604,7 @@ private void dtoa( int binExp, long fractBits, int nSignificantBits, boolean isC // oops. Usually ignore leading zero. decExp--; } else { - digits[ndigit++] = (char)('0' + q); + digits[ndigit++] = (byte)('0' + q); } // // HACK! Java spec sez that we always have at least @@ -708,7 +632,7 @@ private void dtoa( int binExp, long fractBits, int nSignificantBits, boolean isC low = true; high = true; } - digits[ndigit++] = (char)('0' + q); + digits[ndigit++] = (byte)('0' + q); } lowDigitDifference = (b<<1) - tens; exactDecimalConversion = (b == 0); @@ -741,7 +665,7 @@ private void dtoa( int binExp, long fractBits, int nSignificantBits, boolean isC // oops. Usually ignore leading zero. decExp--; } else { - digits[ndigit++] = (char)('0' + q); + digits[ndigit++] = (byte)('0' + q); } // // HACK! Java spec sez that we always have at least @@ -758,7 +682,7 @@ private void dtoa( int binExp, long fractBits, int nSignificantBits, boolean isC Mval = Mval.multBy10(); //Mval = Mval.mult( 10 ); low = (Bval.cmp( Mval ) < 0); high = tenSval.addAndCmp(Bval,Mval)<=0; - digits[ndigit++] = (char)('0' + q); + digits[ndigit++] = (byte)('0' + q); } if ( high && low ){ Bval = Bval.leftShift(1); @@ -812,7 +736,7 @@ private void roundup() { } // else fall through. } - digits[i] = (char) (q + 1); + digits[i] = (byte) (q + 1); decimalDigitsRoundedUp = true; } @@ -845,19 +769,8 @@ static int estimateDecExp(long fractBits, int binExp) { } } - private static int insignificantDigits(long insignificant) { - int i; - for ( i = 0; insignificant >= 10L; i++ ) { - insignificant /= 10L; - } - return i; - } - /** * Calculates - *
-         * insignificantDigitsForPow2(v) == insignificantDigits(1L<
          */
         private static int insignificantDigitsForPow2(int p2) {
             if (p2 > 1 && p2 < insignificantDigitsNumber.length) {
@@ -913,7 +826,14 @@ private static int insignificantDigitsForPow2(int p2) {
                 61,
         };
 
-        private int getChars(char[] result) {
+        /**
+         * Converts the decimal representation of a floating-point number into its
+         * ASCII character representation and stores it in the provided byte array.
+         *
+         * @param result the byte array to store the ASCII representation, must have length at least 26
+         * @return the number of characters written to the result array
+         */
+        public int getChars(byte[] result) {
             assert nDigits <= 19 : nDigits; // generous bound on size of nDigits
             int i = 0;
             if (isNegative) {
@@ -927,7 +847,7 @@ private int getChars(char[] result) {
                 i += charLength;
                 if (charLength < decExponent) {
                     charLength = decExponent - charLength;
-                    Arrays.fill(result,i,i+charLength,'0');
+                    Arrays.fill(result, i, i + charLength, (byte) '0');
                     i += charLength;
                     result[i++] = '.';
                     result[i++] = '0';
@@ -935,7 +855,7 @@ private int getChars(char[] result) {
                     result[i++] = '.';
                     if (charLength < nDigits) {
                         int t = nDigits - charLength;
-                        System.arraycopy(digits, firstDigitIndex+charLength, result, i, t);
+                        System.arraycopy(digits, firstDigitIndex + charLength, result, i, t);
                         i += t;
                     } else {
                         result[i++] = '0';
@@ -945,7 +865,7 @@ private int getChars(char[] result) {
                 result[i++] = '0';
                 result[i++] = '.';
                 if (decExponent != 0) {
-                    Arrays.fill(result, i, i-decExponent, '0');
+                    Arrays.fill(result, i, i-decExponent, (byte) '0');
                     i -= decExponent;
                 }
                 System.arraycopy(digits, firstDigitIndex, result, i, nDigits);
@@ -969,15 +889,15 @@ private int getChars(char[] result) {
                 }
                 // decExponent has 1, 2, or 3, digits
                 if (e <= 9) {
-                    result[i++] = (char) (e + '0');
+                    result[i++] = (byte) (e + '0');
                 } else if (e <= 99) {
-                    result[i++] = (char) (e / 10 + '0');
-                    result[i++] = (char) (e % 10 + '0');
+                    result[i++] = (byte) (e / 10 + '0');
+                    result[i++] = (byte) (e % 10 + '0');
                 } else {
-                    result[i++] = (char) (e / 100 + '0');
+                    result[i++] = (byte) (e / 100 + '0');
                     e %= 100;
-                    result[i++] = (char) (e / 10 + '0');
-                    result[i++] = (char) (e % 10 + '0');
+                    result[i++] = (byte) (e / 10 + '0');
+                    result[i++] = (byte) (e % 10 + '0');
                 }
             }
             return i;
@@ -1043,10 +963,10 @@ public float floatValue() {
      * A buffered implementation of ASCIIToBinaryConverter.
      */
     static class ASCIIToBinaryBuffer implements ASCIIToBinaryConverter {
-        boolean     isNegative;
-        int         decExponent;
-        byte[]      digits;
-        int         nDigits;
+        final boolean isNegative;
+        final int     decExponent;
+        final byte[]  digits;
+        int           nDigits;
 
         ASCIIToBinaryBuffer( boolean negSign, int decExponent, byte[] digits, int n)
         {
@@ -1765,10 +1685,10 @@ private static BinaryToASCIIConverter getBinaryToASCIIConverter(double d) {
         buf.decimalDigitsRoundedUp = dec.getAway();
 
         long f = dec.getSignificand();
-        char[] digits = buf.digits;
+        byte[] digits = buf.digits;
         for (int i = buf.nDigits - 1; i >= 0; --i) {
             long q = f / 10;
-            digits[i] = (char) ((f - 10 * q) + '0');
+            digits[i] = (byte) ((f - 10 * q) + '0');
             f = q;
         }
         return buf;
@@ -1819,58 +1739,14 @@ private static BinaryToASCIIConverter getCompatBinaryToASCIIConverter(double d,
         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;
-    }
-
-    static ASCIIToBinaryConverter readDoubleSignlessDigits(int decExp, char[] digits, int length) {
+    static ASCIIToBinaryConverter readDoubleSignlessDigits(int decExp, byte[] digits, int length) {
 
         // Prevent an extreme negative exponent from causing overflow issues in doubleValue().
         // Large positive values are handled within doubleValue();
         if (decExp < MIN_DECIMAL_EXPONENT) {
             return A2BC_POSITIVE_ZERO;
         }
-        byte[] buf = new byte[length];
-        for (int i = 0; i < length; i++) {
-            buf[i] = (byte) digits[i];
-        }
-        return new ASCIIToBinaryBuffer(false, decExp, buf, length);
+        return new ASCIIToBinaryBuffer(false, decExp, digits, length);
     }
 
     /**