Skip to content

Commit 7c65048

Browse files
committed
8305343: BigDecimal.fractionOnly() erroneously returns true for large scale value
Reviewed-by: darcy
1 parent dd59471 commit 7c65048

File tree

2 files changed

+36
-5
lines changed

2 files changed

+36
-5
lines changed

src/java.base/share/classes/java/math/BigDecimal.java

+10-3
Original file line numberDiff line numberDiff line change
@@ -3596,7 +3596,7 @@ public long longValue(){
35963596
*/
35973597
private boolean fractionOnly() {
35983598
assert this.signum() != 0;
3599-
return (this.precision() - this.scale) <= 0;
3599+
return this.precision() <= this.scale;
36003600
}
36013601

36023602
/**
@@ -3624,8 +3624,15 @@ public long longValueExact() {
36243624
if (fractionOnly())
36253625
throw new ArithmeticException("Rounding necessary");
36263626

3627-
// If more than 19 digits in integer part it cannot possibly fit
3628-
if ((precision() - scale) > 19) // [OK for negative scale too]
3627+
/*
3628+
* If more than 19 digits in integer part it cannot possibly fit.
3629+
* Ensure that arithmetic does not overflow, so instead of
3630+
* precision() - scale > 19
3631+
* prefer
3632+
* precision() - 19 > scale
3633+
* since precision() > 0, so the lhs cannot overflow.
3634+
*/
3635+
if (precision() - 19 > scale) // [OK for negative scale too]
36293636
throw new java.lang.ArithmeticException("Overflow");
36303637

36313638
// round to an integer, with Exception if decimal part non-0

test/jdk/java/math/BigDecimal/LongValueExactTests.java

+26-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2005, 2023, 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,7 @@
2323

2424
/**
2525
* @test
26-
* @bug 6806261 8211936
26+
* @bug 6806261 8211936 8305343
2727
* @summary Tests of BigDecimal.longValueExact
2828
*/
2929
import java.math.*;
@@ -37,6 +37,7 @@ public static void main(String... args) {
3737

3838
failures += longValueExactSuccessful();
3939
failures += longValueExactExceptional();
40+
failures += longValueExactExceptional8305343();
4041

4142
if (failures > 0) {
4243
throw new RuntimeException("Incurred " + failures +
@@ -117,4 +118,27 @@ private static int longValueExactExceptional() {
117118
}
118119
return failures;
119120
}
121+
122+
private static int longValueExactExceptional8305343() {
123+
int failures = 0;
124+
List<BigDecimal> exceptionalCases =
125+
List.of(new BigDecimal("1e" + (Integer.MAX_VALUE - 1)),
126+
new BigDecimal("1e" + (Integer.MAX_VALUE))
127+
);
128+
129+
for (BigDecimal bd : exceptionalCases) {
130+
try {
131+
bd.longValueExact();
132+
failures++;
133+
System.err.println("Unexpected non-exceptional longValueExact on " + bd);
134+
} catch (ArithmeticException e) {
135+
if (!e.getMessage().toLowerCase().contains("overflow")) {
136+
failures++;
137+
System.err.println("Unexpected non-exceptional longValueExact on " + bd);
138+
}
139+
}
140+
}
141+
return failures;
142+
}
143+
120144
}

0 commit comments

Comments
 (0)