Skip to content

Commit deb7edb

Browse files
committed
8366017: Extend the set of inputs handled by fast paths in FloatingDecimal
Reviewed-by: darcy
1 parent 400f51f commit deb7edb

File tree

9 files changed

+1589
-2199
lines changed

9 files changed

+1589
-2199
lines changed

src/java.base/share/classes/java/text/DigitList.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ void set(boolean isNegative, double source, int maximumFractionDigits) {
322322
void set(boolean isNegative, double source, int maximumDigits, boolean fixedPoint) {
323323
assert Double.isFinite(source);
324324

325-
FloatingDecimal.BinaryToASCIIConverter fdConverter =
325+
FloatingDecimal.BinaryToASCIIBuffer fdConverter =
326326
FloatingDecimal.getBinaryToASCIIConverter(source, COMPAT);
327327
boolean hasBeenRoundedUp = fdConverter.digitsRoundedUp();
328328
boolean valueExactAsDecimal = fdConverter.decimalDigitsExact();

src/java.base/share/classes/jdk/internal/math/FDBigInteger.java

Lines changed: 354 additions & 868 deletions
Large diffs are not rendered by default.

src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java

Lines changed: 613 additions & 916 deletions
Large diffs are not rendered by default.

src/java.base/share/classes/jdk/internal/math/MathUtils.java

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ final class MathUtils {
4343
*/
4444

4545
/*
46-
* N = max{n : 10^n - 1 <= 2^Long.SIZE - 1}
46+
* N = max{n : 10^n - 1 2^Long.SIZE - 1}
4747
* Every positive integer up to N decimal digits fits in an unsigned long,
4848
* but there are positive integers of N + 1 digits that do not.
4949
*/
@@ -52,16 +52,16 @@ final class MathUtils {
5252
/*
5353
* Given integer e, let 10^e = beta 2^r for the unique integer r and
5454
* real beta meeting
55-
* 2^125 <= beta < 2^126.
55+
* 2^125 beta < 2^126.
5656
* The unique r and beta are
5757
* r = floor(log2(10^e)) - 125, beta = 10^e 2^(-r)
5858
* Let g = floor(beta) + 1.
5959
* Thus,
60-
* (g - 1) 2^r <= 10^e < g 2^r
60+
* (g - 1) 2^r 10^e < g 2^r
6161
* Further, let
6262
* g1 = floor(g 2^(-63)), g0 = g - g1 2^63
6363
*
64-
* For e with GE_MIN <= e <= GE_MAX, the values g1 and g0 are available
64+
* For e with GE_MIN e GE_MAX, the values g1 and g0 are available
6565
* by invoking methods g1(e) and g0(e).
6666
* In addition, r = flog2pow10(e) - 125.
6767
*
@@ -73,17 +73,27 @@ final class MathUtils {
7373
* discussed in [1].
7474
* (See DoubleToDecimal.K_MIN and DoubleToDecimal.K_MAX.)
7575
*
76-
* Let x = f 10^ep, where integers f and ep meet 10^(n-1) <= f < 10^n
76+
* Let x = f 10^ep, where integers f and ep meet 10^(n-1) f < 10^n
7777
* (that is, f has n digits) and E_THR_Z < ep + n < E_THR_I.
7878
* (See DoubleToDecimal.E_THR_Z and DoubleToDecimal.E_THR_I.)
7979
*
80-
* The decimal->double fast paths assume n <= N.
81-
* Thus, E_THR_Z - (N - 1) <= ep <= E_THR_I - 2, which means that
80+
* The decimal->double fast paths assume n N.
81+
* Thus, E_THR_Z - (N - 1) ep E_THR_I - 2, which means that
8282
* the interval [GE_MIN, GE_MAX] must include the interval
8383
* [E_THR_Z - (N - 1), E_THR_I - 2].
8484
* That is,
8585
* GE_MIN = min(-K_MAX, E_THR_Z - (N - 1))
8686
* GE_MAX = max(-K_MIN, E_THR_I - 2)
87+
*
88+
* For the record, while the definition of g allows the case g = 2^126,
89+
* the maximal g1 in the lookup table is 0x7FDD_E7F4_CA72_E30FL (e = -146),
90+
* the minimal g1 is 0x4000_0000_0000_0000L (for e = 0),
91+
* and the minimal g0 is 1.
92+
* Hence, as easily verified, we always have
93+
* 2^62 < g1 + 1 < 2^31 (2^32 - 1) < 2^63
94+
* 2^125 < g = g1 2^63 + g0 < (g1 + 1) 2^63 < 2^94 (2^32 - 1) < 2^126
95+
* We will assume these bounds observed by glancing at the lookup table,
96+
* and use them liberally when so needed.
8797
*/
8898
static final int GE_MIN = -342;
8999
static final int GE_MAX = 324;

test/jdk/java/lang/Double/ParseDouble.java

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,8 @@
2323

2424
/*
2525
* @test
26-
* @bug 4160406 4705734 4707389 4826774 4895911 4421494 6358355 7021568 7039369 4396272
26+
* @bug 4160406 4705734 4707389 4826774 4895911 4421494 6358355 7021568
27+
* 7039369 4396272 8366017
2728
* @summary Test for Double.parseDouble method and acceptance regex
2829
*/
2930

@@ -759,6 +760,39 @@ private static void testStrictness() {
759760
throw new RuntimeException("Inconsistent conversion");
760761
}
761762

763+
private static void testFastPaths() {
764+
/* Exercises the fast paths in jdk.internal.math.FloatingDecimal. */
765+
check("1", 0x1.0p0); // 1.0
766+
check("2.34000e2", 0x1.d4p7); // 234.0
767+
check("9.223e18", 0x1.fffab689adb6p62); // 9.223e18
768+
check("9.876e18", 0x1.121d33597384p63); // 9.876e18
769+
check("9223372036854776833", 0x1.0000000000001p63); // 9.223372036854778E18
770+
check("9223372036854776832", 0x1.0p63); // 9.223372036854776E18
771+
772+
check("1.23", 0x1.3ae147ae147aep0); // 1.23
773+
check("0.000234", 0x1.eabbcb1cc9646p-13); // 2.34E-4
774+
check("3.45e23", 0x1.2439f32cbea41p78); // 3.45E23
775+
check("576460752303423616e20", 0x1.5af1d78b58c41p125); // 5.764607523034236E37
776+
777+
check("1e37", 0x1.e17b84357691bp122); // 1.0E37
778+
check("8999e34", 0x1.0ecdc63717fbdp126); // 8.999E37
779+
check("0.9999e36", 0x1.8125c09cb78b7p119); // 9.999E35
780+
check("0.9876e37", 0x1.db831933296cep122); // 9.876E36
781+
782+
check("1.2e-200", 0x1.d64af4cc52935p-665); // 1.2E-200
783+
check("2.3e100", 0x1.507ed84d17a69p333); // 2.3E100
784+
check("1.2000000000000000003e-200", 0x1.d64af4cc52935p-665); // 1.2E-200
785+
check("2.3000000000000000004e100", 0x1.507ed84d17a69p333); // 2.3E100
786+
check("5.249320425370670463e308", Double.POSITIVE_INFINITY);
787+
check("5.2493204253706704633e308", Double.POSITIVE_INFINITY);
788+
789+
check("1.2e-320", 0x0.000000000097dp-1022); // 1.2E-320
790+
check("1.2000000000000000003e-320", 0x0.000000000097dp-1022); // 1.2E-320
791+
792+
check("2.225073858507201383e-308", Double.MIN_NORMAL);
793+
check("2.2250738585072013831e-308", Double.MIN_NORMAL);
794+
}
795+
762796
public static void main(String[] args) throws Exception {
763797
rudimentaryTest();
764798

@@ -775,5 +809,8 @@ public static void main(String[] args) throws Exception {
775809
testSubnormalPowers();
776810
testPowers();
777811
testStrictness();
812+
813+
testFastPaths();
778814
}
815+
779816
}

test/jdk/java/lang/Float/ParseFloat.java

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -23,8 +23,10 @@
2323

2424
/*
2525
* @test
26-
* @bug 4160406 4705734 4707389 6358355 7032154
27-
* @summary Tests for Float.parseFloat method
26+
* @bug 4160406 4705734 4707389 6358355 7032154 8366017
27+
* @summary Tests for Float.parseFloat method (use -DallRoundtrips=true
28+
* to additionally check all non-negative, non-NaN float->String->float
29+
* roundtrips)
2830
*/
2931

3032
import java.math.BigDecimal;
@@ -315,6 +317,22 @@ private static void testPowers() {
315317
check(new BigDecimal(Float.MAX_VALUE).add(new BigDecimal(Math.ulp(Float.MAX_VALUE)).multiply(HALF)).toString());
316318
}
317319

320+
private static final int N = Float.floatToIntBits(Float.POSITIVE_INFINITY);
321+
322+
/* Tests all non-negative, non-NaN float->String->float roundtrips. */
323+
private static void testAllRoundtrips() {
324+
for (int i = 0; i <= N; ++i) {
325+
float v = Float.intBitsToFloat(i);
326+
String s = Float.toString(v);
327+
float v0 = Float.parseFloat(s);
328+
if (v != v0) {
329+
fail(s, v0);
330+
}
331+
}
332+
}
333+
334+
private static final String ALL_ROUNDTRIPS_PROP = "allRoundtrips";
335+
318336
public static void main(String[] args) throws Exception {
319337
rudimentaryTest();
320338

@@ -324,5 +342,9 @@ public static void main(String[] args) throws Exception {
324342
testParsing(paddedBadStrings, true);
325343

326344
testPowers();
345+
346+
if (Boolean.getBoolean(ALL_ROUNDTRIPS_PROP)) {
347+
testAllRoundtrips();
348+
}
327349
}
328350
}

0 commit comments

Comments
 (0)