undefect. CWE-407 — 63 sites patched across 27 ecosystems

Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
This commit is contained in:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View file

@ -0,0 +1,327 @@
/*
* Copyright (c) 2006, 2025, 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.
*
* 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.
*/
/*
* @test
* @bug 6362557 8200698
* @summary Some tests of add(BigDecimal, mc)
*/
import java.math.*;
import static java.math.BigDecimal.*;
import java.util.Set;
import java.util.EnumSet;
public class AddTests {
private static Set<RoundingMode> nonExactRoundingModes =
EnumSet.complementOf(EnumSet.of(RoundingMode.UNNECESSARY));
/**
* Test for some simple additions, particularly, it will test
* the overflow case.
*/
private static int simpleTests() {
int failures = 0;
BigDecimal[] bd1 = {
new BigDecimal(new BigInteger("7812404666936930160"), 11),
new BigDecimal(new BigInteger("7812404666936930160"), 12),
new BigDecimal(new BigInteger("7812404666936930160"), 13),
};
BigDecimal bd2 = new BigDecimal(new BigInteger("2790000"), 1);
BigDecimal[] expectedResult = {
new BigDecimal("78403046.66936930160"),
new BigDecimal("8091404.666936930160"),
new BigDecimal("1060240.4666936930160"),
};
for (int i = 0; i < bd1.length; i++) {
if (!bd1[i].add(bd2).equals(expectedResult[i]))
failures++;
}
return failures;
}
/**
* Test for extreme value of scale and rounding precision that
* could cause integer overflow in right-shift-into-sticky-bit
* computations.
*/
private static int extremaTests() {
int failures = 0;
failures += addWithoutException(valueOf(1, -Integer.MAX_VALUE),
valueOf(2, Integer.MAX_VALUE), null);
failures += addWithoutException(valueOf(1, -Integer.MAX_VALUE),
valueOf(-2, Integer.MAX_VALUE), null);
return failures;
}
/**
* Print sum of b1 and b2; correct result will not throw an
* exception.
*/
private static int addWithoutException(BigDecimal b1, BigDecimal b2, MathContext mc) {
if (mc == null)
mc = new MathContext(2, RoundingMode.DOWN);
try {
BigDecimal sum = b1.add(b2, mc);
printAddition(b1, b2, sum.toString());
return 0;
} catch(ArithmeticException ae) {
printAddition(b1, b2, "Exception!");
return 1;
}
}
/**
* Test combinations of operands that may meet the condensation
* criteria when rounded to different precisions.
*/
private static int roundingGradationTests() {
int failures = 0;
failures += roundAway(new BigDecimal("1234e100"),
new BigDecimal( "1234e97"));
failures += roundAway(new BigDecimal("1234e100"),
new BigDecimal( "1234e96"));
failures += roundAway(new BigDecimal("1234e100"),
new BigDecimal( "1234e95"));
failures += roundAway(new BigDecimal("1234e100"),
new BigDecimal( "1234e94"));
failures += roundAway(new BigDecimal("1234e100"),
new BigDecimal( "1234e93"));
failures += roundAway(new BigDecimal("1234e100"),
new BigDecimal( "1234e92"));
failures += roundAway(new BigDecimal("1234e100"),
new BigDecimal("1234e50"));
failures += roundAway(new BigDecimal("1000e100"),
new BigDecimal( "1234e97"));
failures += roundAway(new BigDecimal("1000e100"),
new BigDecimal( "1234e96"));
failures += roundAway(new BigDecimal("1000e100"),
new BigDecimal( "1234e95"));
failures += roundAway(new BigDecimal("1000e100"),
new BigDecimal( "1234e94"));
failures += roundAway(new BigDecimal("1000e100"),
new BigDecimal( "1234e93"));
failures += roundAway(new BigDecimal("1000e100"),
new BigDecimal( "1234e92"));
failures += roundAway(new BigDecimal("1000e100"),
new BigDecimal("1234e50"));
failures += roundAway(new BigDecimal("1999e100"),
new BigDecimal( "1234e97"));
failures += roundAway(new BigDecimal("1999e100"),
new BigDecimal( "1234e96"));
failures += roundAway(new BigDecimal("1999e100"),
new BigDecimal( "1234e95"));
failures += roundAway(new BigDecimal("1999e100"),
new BigDecimal( "1234e94"));
failures += roundAway(new BigDecimal("1999e100"),
new BigDecimal( "1234e93"));
failures += roundAway(new BigDecimal("1999e100"),
new BigDecimal( "1234e92"));
failures += roundAway(new BigDecimal("1999e100"),
new BigDecimal("1234e50"));
failures += roundAway(new BigDecimal("9999e100"),
new BigDecimal( "1234e97"));
failures += roundAway(new BigDecimal("9999e100"),
new BigDecimal( "1234e96"));
failures += roundAway(new BigDecimal("9999e100"),
new BigDecimal( "1234e95"));
failures += roundAway(new BigDecimal("9999e100"),
new BigDecimal( "1234e94"));
failures += roundAway(new BigDecimal("9999e100"),
new BigDecimal( "1234e93"));
failures += roundAway(new BigDecimal("9999e100"),
new BigDecimal( "1234e92"));
failures += roundAway(new BigDecimal("9999e100"),
new BigDecimal("1234e50"));
return failures;
}
private static void printAddition(BigDecimal b1, BigDecimal b2, String s) {
System.out.println("" + b1+ "\t+\t" + b2 + "\t=\t" + s);
}
private static int roundAway(BigDecimal b1, BigDecimal b2) {
int failures = 0;
b1.precision();
b2.precision();
BigDecimal b1_negate = b1.negate();
BigDecimal b2_negate = b2.negate();
b1_negate.precision();
b2_negate.precision();
failures += roundAway1(b1, b2);
failures += roundAway1(b1, b2_negate);
failures += roundAway1(b1_negate, b2);
failures += roundAway1(b1_negate, b2_negate);
return failures;
}
private static int roundAway1(BigDecimal b1, BigDecimal b2) {
int failures = 0;
failures += roundAway0(b1, b2);
failures += roundAway0(b2, b1);
return failures;
}
/**
* Compare b1.add(b2, mc) with b1.add(b2).round(mc) for a variety
* of MathContexts.
*/
private static int roundAway0(BigDecimal b1, BigDecimal b2) {
int failures = 0;
BigDecimal exactSum = b1.add(b2);
for(int precision = 1 ; precision < exactSum.precision()+2; precision++) {
for(RoundingMode rm : nonExactRoundingModes) {
MathContext mc = new MathContext(precision, rm);
BigDecimal roundedExactSum = exactSum.round(mc);
try {
BigDecimal sum = b1.add(b2, mc);
if (!roundedExactSum.equals(sum) ) {
failures++;
System.out.println("Exact sum " + exactSum +
"\trounded by " + mc +
"\texpected: " + roundedExactSum + " got: ");
printAddition(b1, b2, sum.toString());
}
// else {
// System.out.print(mc + "\t");
// printAddition(b1, b2, sum.toString());
// }
} catch (ArithmeticException ae) {
printAddition(b1, b2, "Exception!");
failures++;
}
}
}
return failures;
}
/**
* Verify calling the precision method should not change the
* computed result.
*/
private static int precisionConsistencyTest() {
int failures = 0;
MathContext mc = new MathContext(1,RoundingMode.DOWN);
BigDecimal a = BigDecimal.valueOf(1999, -1); //value is equivalent to 19990
BigDecimal sum1 = a.add(BigDecimal.ONE, mc);
a.precision();
BigDecimal sum2 = a.add(BigDecimal.ONE, mc);
if (!sum1.equals(sum2)) {
failures ++;
System.out.println("Unequal sums after calling precision!");
System.out.print("Before:\t");
printAddition(a, BigDecimal.ONE, sum1.toString());
System.out.print("After:\t");
printAddition(a, BigDecimal.ONE, sum2.toString());
}
return failures;
}
private static int arithmeticExceptionTest() {
int failures = 0;
BigDecimal x;
try {
//
// The string representation "1e2147483647", which is equivalent
// to 10^Integer.MAX_VALUE, is used to create an augend with an
// unscaled value of 1 and a scale of -Integer.MAX_VALUE. The
// addend "1" has an unscaled value of 1 with a scale of 0. The
// addition is performed exactly and is specified to have a
// preferred scale of max(-Integer.MAX_VALUE, 0). As the scale
// of the result is 0, a value with Integer.MAX_VALUE + 1 digits
// would need to be created. Therefore the next statement is
// expected to overflow with an ArithmeticException.
//
x = new BigDecimal("1e2147483647").add(new BigDecimal(1));
failures++;
} catch (ArithmeticException ae) {
}
return failures;
}
public static void main(String argv[]) {
int failures = 0;
failures += extremaTests();
failures += roundingGradationTests();
failures += precisionConsistencyTest();
failures += arithmeticExceptionTest();
if (failures > 0) {
throw new RuntimeException("Incurred " + failures +
" failures while testing rounding add.");
}
}
}

View file

@ -0,0 +1,115 @@
/*
* Copyright (c) 2006, 2025, 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.
*
* 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.
*/
/*
* @test
* @bug 6473768
* @summary Tests of BigDecimal.compareTo
*/
import java.math.*;
import static java.math.BigDecimal.*;
public class CompareToTests {
private static int compareToTests() {
int failures = 0;
final BigDecimal MINUS_ONE = BigDecimal.ONE.negate();
// First operand, second operand, expected compareTo result
BigDecimal [][] testCases = {
// Basics
{valueOf(0), valueOf(0), ZERO},
{valueOf(0), valueOf(1), MINUS_ONE},
{valueOf(1), valueOf(2), MINUS_ONE},
{valueOf(2), valueOf(1), ONE},
{valueOf(10), valueOf(10), ZERO},
// Significands would compare differently than scaled value
{valueOf(2,1), valueOf(2), MINUS_ONE},
{valueOf(2,-1), valueOf(2), ONE},
{valueOf(1,1), valueOf(2), MINUS_ONE},
{valueOf(1,-1), valueOf(2), ONE},
{valueOf(5,-1), valueOf(2), ONE},
// Boundary and near boundary values
{valueOf(Long.MAX_VALUE), valueOf(Long.MAX_VALUE), ZERO},
{valueOf(Long.MAX_VALUE).negate(), valueOf(Long.MAX_VALUE), MINUS_ONE},
{valueOf(Long.MAX_VALUE-1), valueOf(Long.MAX_VALUE), MINUS_ONE},
{valueOf(Long.MAX_VALUE-1).negate(), valueOf(Long.MAX_VALUE), MINUS_ONE},
{valueOf(Long.MIN_VALUE), valueOf(Long.MAX_VALUE), MINUS_ONE},
{valueOf(Long.MIN_VALUE).negate(), valueOf(Long.MAX_VALUE), ONE},
{valueOf(Long.MIN_VALUE+1), valueOf(Long.MAX_VALUE), MINUS_ONE},
{valueOf(Long.MIN_VALUE+1).negate(), valueOf(Long.MAX_VALUE), ZERO},
{valueOf(Long.MAX_VALUE), valueOf(Long.MIN_VALUE), ONE},
{valueOf(Long.MAX_VALUE).negate(), valueOf(Long.MIN_VALUE), ONE},
{valueOf(Long.MAX_VALUE-1), valueOf(Long.MIN_VALUE), ONE},
{valueOf(Long.MAX_VALUE-1).negate(), valueOf(Long.MIN_VALUE), ONE},
{valueOf(Long.MIN_VALUE), valueOf(Long.MIN_VALUE), ZERO},
{valueOf(Long.MIN_VALUE).negate(), valueOf(Long.MIN_VALUE), ONE},
{valueOf(Long.MIN_VALUE+1), valueOf(Long.MIN_VALUE), ONE},
{valueOf(Long.MIN_VALUE+1).negate(), valueOf(Long.MIN_VALUE), ONE},
};
for (BigDecimal[] testCase : testCases) {
BigDecimal a = testCase[0];
BigDecimal a_negate = a.negate();
BigDecimal b = testCase[1];
BigDecimal b_negate = b.negate();
int expected = testCase[2].intValue();
failures += compareToTest(a, b, expected);
failures += compareToTest(a_negate, b_negate, -expected);
}
return failures;
}
private static int compareToTest(BigDecimal a, BigDecimal b, int expected) {
int result = a.compareTo(b);
int failed = (result==expected) ? 0 : 1;
if (failed == 1) {
System.err.println("(" + a + ").compareTo(" + b + ") => " + result +
"\n\tExpected " + expected);
}
return failed;
}
public static void main(String argv[]) {
int failures = 0;
failures += compareToTests();
if (failures > 0) {
throw new RuntimeException("Incurred " + failures +
" failures while testing exact compareTo.");
}
}
}

View file

@ -0,0 +1,82 @@
/*
* Copyright (c) 1999, 2025, 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.
*
* 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.
*/
/*
* @test
* @bug 4259453 8200698
* @summary Test constructors of BigDecimal
* @library ..
* @run junit Constructor
*/
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.math.BigDecimal;
public class Constructor {
@Test
public void stringConstructor() {
Assertions.assertThrows(NumberFormatException.class, () -> {
BigDecimal bd = new BigDecimal("1.2e");
});
}
@Test
public void charArrayConstructorNegativeOffset() {
Assertions.assertThrows(NumberFormatException.class, () -> {
BigDecimal bd = new BigDecimal(new char[5], -1, 4, null);
});
}
@Test
public void charArrayConstructorNegativeLength() {
Assertions.assertThrows(NumberFormatException.class, () -> {
BigDecimal bd = new BigDecimal(new char[5], 0, -1, null);
});
}
@Test
public void charArrayConstructorIntegerOverflow() {
Assertions.assertThrows(NumberFormatException.class, () -> {
try {
BigDecimal bd = new BigDecimal(new char[5], Integer.MAX_VALUE - 5,
6, null);
} catch (NumberFormatException nfe) {
if (nfe.getCause() instanceof IndexOutOfBoundsException) {
throw new RuntimeException
("NumberFormatException should not have a cause");
} else {
throw nfe;
}
}
});
}
@Test
public void charArrayConstructorIndexOutOfBounds() {
Assertions.assertThrows(NumberFormatException.class, () -> {
BigDecimal bd = new BigDecimal(new char[5], 1, 5, null);
});
}
}

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2022, 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.
*
* 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.
*/
/*
* @test
* @bug 8282252
* @summary Test constructors of BigDecimal to replace BigInteger subclasses
*/
import java.math.*;
public class ConstructorUnscaledValue {
public static void main(String... args) {
TestBigInteger tbi = new TestBigInteger(BigInteger.ONE);
// Create BigDecimal's using each of the three constructors
// with guards on the class of unscaledValue
BigDecimal[] values = {
new BigDecimal(tbi),
new BigDecimal(tbi, 2),
new BigDecimal(tbi, 3, MathContext.DECIMAL32),
};
for (var bd : values) {
BigInteger unscaledValue = bd.unscaledValue();
if (unscaledValue.getClass() != BigInteger.class) {
throw new RuntimeException("Bad class for unscaledValue");
}
if (!unscaledValue.equals(BigInteger.ONE)) {
throw new RuntimeException("Bad value for unscaledValue");
}
}
}
private static class TestBigInteger extends BigInteger {
public TestBigInteger(BigInteger bi) {
super(bi.toByteArray());
}
@Override
public String toString() {
return java.util.Arrays.toString(toByteArray());
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,426 @@
/*
* Copyright (c) 2003, 2025, 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.
*
* 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.
*/
/*
* @test
* @bug 4851776 4907265 6177836 6876282 8066842
* @summary Some tests for the divide methods.
*/
import java.math.*;
import static java.math.BigDecimal.*;
public class DivideTests {
// Preliminary exact divide method; could be used for comparison
// purposes.
BigDecimal anotherDivide(BigDecimal dividend, BigDecimal divisor) {
/*
* Handle zero cases first.
*/
if (divisor.signum() == 0) { // x/0
if (dividend.signum() == 0) // 0/0
throw new ArithmeticException("Division undefined"); // NaN
throw new ArithmeticException("Division by zero");
}
if (dividend.signum() == 0) // 0/y
return BigDecimal.ZERO;
else {
/*
* Determine if there is a result with a terminating
* decimal expansion. Putting aside overflow and
* underflow considerations, the existance of an exact
* result only depends on the ratio of the intVal's of the
* dividend (i.e. this) and divisor since the scales
* of the argument just affect where the decimal point
* lies.
*
* For the ratio of (a = this.intVal) and (b =
* divisor.intVal) to have a finite decimal expansion,
* once a/b is put in lowest terms, b must be equal to
* (2^i)*(5^j) for some integer i,j >= 0. Therefore, we
* first compute to see if b_prime =(b/gcd(a,b)) is equal
* to (2^i)*(5^j).
*/
BigInteger TWO = BigInteger.valueOf(2);
BigInteger FIVE = BigInteger.valueOf(5);
BigInteger TEN = BigInteger.valueOf(10);
BigInteger divisorIntvalue = divisor.scaleByPowerOfTen(divisor.scale()).toBigInteger().abs();
BigInteger dividendIntvalue = dividend.scaleByPowerOfTen(dividend.scale()).toBigInteger().abs();
BigInteger b_prime = divisorIntvalue.divide(dividendIntvalue.gcd(divisorIntvalue));
boolean goodDivisor = false;
int i=0, j=0;
badDivisor: {
while(! b_prime.equals(BigInteger.ONE) ) {
int b_primeModTen = b_prime.mod(TEN).intValue() ;
switch(b_primeModTen) {
case 0:
// b_prime divisible by 10=2*5, increment i and j
i++;
j++;
b_prime = b_prime.divide(TEN);
break;
case 5:
// b_prime divisible by 5, increment j
j++;
b_prime = b_prime.divide(FIVE);
break;
case 2:
case 4:
case 6:
case 8:
// b_prime divisible by 2, increment i
i++;
b_prime = b_prime.divide(TWO);
break;
default: // hit something we shouldn't have
b_prime = BigInteger.ONE; // terminate loop
break badDivisor;
}
}
goodDivisor = true;
}
if( ! goodDivisor ) {
throw new ArithmeticException("Non terminating decimal expansion");
}
else {
// What is a rule for determining how many digits are
// needed? Once that is determined, cons up a new
// MathContext object and pass it on to the divide(bd,
// mc) method; precision == ?, roundingMode is unnecessary.
// Are we sure this is the right scale to use? Should
// also determine a precision-based method.
MathContext mc = new MathContext(dividend.precision() +
(int)Math.ceil(
10.0*divisor.precision()/3.0),
RoundingMode.UNNECESSARY);
// Should do some more work here to rescale, etc.
return dividend.divide(divisor, mc);
}
}
}
public static int powersOf2and5() {
int failures = 0;
for(int i = 0; i < 6; i++) {
int powerOf2 = (int)StrictMath.pow(2.0, i);
for(int j = 0; j < 6; j++) {
int powerOf5 = (int)StrictMath.pow(5.0, j);
int product;
BigDecimal bd;
try {
bd = BigDecimal.ONE.divide(new BigDecimal(product=powerOf2*powerOf5));
} catch (ArithmeticException e) {
failures++;
System.err.println((new BigDecimal(powerOf2)).toString() + " / " +
(new BigDecimal(powerOf5)).toString() + " threw an exception.");
e.printStackTrace();
}
try {
bd = new BigDecimal(powerOf2).divide(new BigDecimal(powerOf5));
} catch (ArithmeticException e) {
failures++;
System.err.println((new BigDecimal(powerOf2)).toString() + " / " +
(new BigDecimal(powerOf5)).toString() + " threw an exception.");
e.printStackTrace();
}
try {
bd = new BigDecimal(powerOf5).divide(new BigDecimal(powerOf2));
} catch (ArithmeticException e) {
failures++;
System.err.println((new BigDecimal(powerOf5)).toString() + " / " +
(new BigDecimal(powerOf2)).toString() + " threw an exception.");
e.printStackTrace();
}
}
}
return failures;
}
public static int nonTerminating() {
int failures = 0;
int[] primes = {1, 3, 7, 13, 17};
// For each pair of prime products, verify the ratio of
// non-equal products has a non-terminating expansion.
for(int i = 0; i < primes.length; i++) {
for(int j = i+1; j < primes.length; j++) {
for(int m = 0; m < primes.length; m++) {
for(int n = m+1; n < primes.length; n++) {
int dividend = primes[i] * primes[j];
int divisor = primes[m] * primes[n];
if ( ((dividend/divisor) * divisor) != dividend ) {
try {
BigDecimal quotient = (new BigDecimal(dividend).
divide(new BigDecimal(divisor)));
failures++;
System.err.println("Exact quotient " + quotient.toString() +
" returned for non-terminating fraction " +
dividend + " / " + divisor + ".");
}
catch (ArithmeticException e) {
; // Correct result
}
}
}
}
}
}
return failures;
}
public static int properScaleTests(){
int failures = 0;
BigDecimal[][] testCases = {
{new BigDecimal("1"), new BigDecimal("5"), new BigDecimal("2e-1")},
{new BigDecimal("1"), new BigDecimal("50e-1"), new BigDecimal("2e-1")},
{new BigDecimal("10e-1"), new BigDecimal("5"), new BigDecimal("2e-1")},
{new BigDecimal("1"), new BigDecimal("500e-2"), new BigDecimal("2e-1")},
{new BigDecimal("100e-2"), new BigDecimal("5"), new BigDecimal("20e-2")},
{new BigDecimal("1"), new BigDecimal("32"), new BigDecimal("3125e-5")},
{new BigDecimal("1"), new BigDecimal("64"), new BigDecimal("15625e-6")},
{new BigDecimal("1.0000000"), new BigDecimal("64"), new BigDecimal("156250e-7")},
};
for(BigDecimal[] tc : testCases) {
BigDecimal quotient;
if (! (quotient = tc[0].divide(tc[1])).equals(tc[2]) ) {
failures++;
System.err.println("Unexpected quotient from " + tc[0] + " / " + tc[1] +
"; expected " + tc[2] + " got " + quotient);
}
}
return failures;
}
public static int trailingZeroTests() {
int failures = 0;
MathContext mc = new MathContext(3, RoundingMode.FLOOR);
BigDecimal[][] testCases = {
{new BigDecimal("19"), new BigDecimal("100"), new BigDecimal("0.19")},
{new BigDecimal("21"), new BigDecimal("110"), new BigDecimal("0.190")},
};
for(BigDecimal[] tc : testCases) {
BigDecimal quotient;
if (! (quotient = tc[0].divide(tc[1], mc)).equals(tc[2]) ) {
failures++;
System.err.println("Unexpected quotient from " + tc[0] + " / " + tc[1] +
"; expected " + tc[2] + " got " + quotient);
}
}
return failures;
}
public static int scaledRoundedDivideTests() {
int failures = 0;
// Tests of the traditional scaled divide under different
// rounding modes.
// Encode rounding mode and scale for the divide in a
// BigDecimal with the significand equal to the rounding mode
// and the scale equal to the number's scale.
// {dividend, dividisor, rounding, quotient}
BigDecimal a = new BigDecimal("31415");
BigDecimal a_minus = a.negate();
BigDecimal b = new BigDecimal("10000");
BigDecimal c = new BigDecimal("31425");
BigDecimal c_minus = c.negate();
// Ad hoc tests
BigDecimal d = new BigDecimal(new BigInteger("-37361671119238118911893939591735"), 10);
BigDecimal e = new BigDecimal(new BigInteger("74723342238476237823787879183470"), 15);
BigDecimal[][] testCases = {
{a, b, BigDecimal.valueOf(ROUND_UP, 3), new BigDecimal("3.142")},
{a_minus, b, BigDecimal.valueOf(ROUND_UP, 3), new BigDecimal("-3.142")},
{a, b, BigDecimal.valueOf(ROUND_DOWN, 3), new BigDecimal("3.141")},
{a_minus, b, BigDecimal.valueOf(ROUND_DOWN, 3), new BigDecimal("-3.141")},
{a, b, BigDecimal.valueOf(ROUND_CEILING, 3), new BigDecimal("3.142")},
{a_minus, b, BigDecimal.valueOf(ROUND_CEILING, 3), new BigDecimal("-3.141")},
{a, b, BigDecimal.valueOf(ROUND_FLOOR, 3), new BigDecimal("3.141")},
{a_minus, b, BigDecimal.valueOf(ROUND_FLOOR, 3), new BigDecimal("-3.142")},
{a, b, BigDecimal.valueOf(ROUND_HALF_UP, 3), new BigDecimal("3.142")},
{a_minus, b, BigDecimal.valueOf(ROUND_HALF_UP, 3), new BigDecimal("-3.142")},
{a, b, BigDecimal.valueOf(ROUND_DOWN, 3), new BigDecimal("3.141")},
{a_minus, b, BigDecimal.valueOf(ROUND_DOWN, 3), new BigDecimal("-3.141")},
{a, b, BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("3.142")},
{a_minus, b, BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("-3.142")},
{c, b, BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("3.142")},
{c_minus, b, BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("-3.142")},
{d, e, BigDecimal.valueOf(ROUND_HALF_UP, -5), BigDecimal.valueOf(-1, -5)},
{d, e, BigDecimal.valueOf(ROUND_HALF_DOWN, -5), BigDecimal.valueOf(0, -5)},
{d, e, BigDecimal.valueOf(ROUND_HALF_EVEN, -5), BigDecimal.valueOf(0, -5)},
};
for(BigDecimal tc[] : testCases) {
int scale = tc[2].scale();
int rm = tc[2].unscaledValue().intValue();
BigDecimal quotient = tc[0].divide(tc[1], scale, rm);
if (!quotient.equals(tc[3])) {
failures++;
System.err.println("Unexpected quotient from " + tc[0] + " / " + tc[1] +
" scale " + scale + " rounding mode " + RoundingMode.valueOf(rm) +
"; expected " + tc[3] + " got " + quotient);
}
}
// 6876282
BigDecimal[][] testCases2 = {
// { dividend, divisor, expected quotient }
{ new BigDecimal(3090), new BigDecimal(7), new BigDecimal(441) },
{ new BigDecimal("309000000000000000000000"), new BigDecimal("700000000000000000000"),
new BigDecimal(441) },
{ new BigDecimal("962.430000000000"), new BigDecimal("8346463.460000000000"),
new BigDecimal("0.000115309916") },
{ new BigDecimal("18446744073709551631"), new BigDecimal("4611686018427387909"),
new BigDecimal(4) },
{ new BigDecimal("18446744073709551630"), new BigDecimal("4611686018427387909"),
new BigDecimal(4) },
{ new BigDecimal("23058430092136939523"), new BigDecimal("4611686018427387905"),
new BigDecimal(5) },
{ new BigDecimal("-18446744073709551661"), new BigDecimal("-4611686018427387919"),
new BigDecimal(4) },
{ new BigDecimal("-18446744073709551660"), new BigDecimal("-4611686018427387919"),
new BigDecimal(4) },
};
for (BigDecimal test[] : testCases2) {
BigDecimal quo = test[0].divide(test[1], RoundingMode.HALF_UP);
if (!quo.equals(test[2])) {
failures++;
System.err.println("Unexpected quotient from " + test[0] + " / " + test[1] +
" rounding mode HALF_UP" +
"; expected " + test[2] + " got " + quo);
}
}
return failures;
}
private static int divideByOneTests() {
int failures = 0;
//problematic divisor: one with scale 17
BigDecimal one = BigDecimal.ONE.setScale(17);
RoundingMode rounding = RoundingMode.UNNECESSARY;
long[][] unscaledAndScale = new long[][] {
{ Long.MAX_VALUE, 17},
{-Long.MAX_VALUE, 17},
{ Long.MAX_VALUE, 0},
{-Long.MAX_VALUE, 0},
{ Long.MAX_VALUE, 100},
{-Long.MAX_VALUE, 100}
};
for (long[] uas : unscaledAndScale) {
long unscaled = uas[0];
int scale = (int)uas[1];
BigDecimal noRound = null;
try {
noRound = BigDecimal.valueOf(unscaled, scale).
divide(one, RoundingMode.UNNECESSARY);
} catch (ArithmeticException e) {
failures++;
System.err.println("ArithmeticException for value " + unscaled
+ " and scale " + scale + " without rounding");
}
BigDecimal roundDown = null;
try {
roundDown = BigDecimal.valueOf(unscaled, scale).
divide(one, RoundingMode.DOWN);
} catch (ArithmeticException e) {
failures++;
System.err.println("ArithmeticException for value " + unscaled
+ " and scale " + scale + " with rounding down");
}
if (noRound != null && roundDown != null
&& noRound.compareTo(roundDown) != 0) {
failures++;
System.err.println("Equality failure for value " + unscaled
+ " and scale " + scale);
}
}
return failures;
}
public static void main(String argv[]) {
int failures = 0;
failures += powersOf2and5();
failures += nonTerminating();
failures += properScaleTests();
failures += trailingZeroTests();
failures += scaledRoundedDivideTests();
failures += divideByOneTests();
if (failures > 0) {
throw new RuntimeException("Incurred " + failures +
" failures while testing division.");
}
}
}

View file

@ -0,0 +1,366 @@
/*
* Copyright (c) 2022, 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.
*
* 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.
*/
/*
* @test
* @bug 8205592 8339252 8341260
* @summary Verify {double, float, float16}Value methods work
* @modules jdk.incubator.vector
* @library /test/lib
* @key randomness
* @build jdk.test.lib.RandomFactory
* @run main DoubleFloatValueTests
*/
import jdk.test.lib.RandomFactory;
import java.math.BigDecimal;
import java.util.Random;
import jdk.incubator.vector.Float16;
public class DoubleFloatValueTests {
private static final BigDecimal HALF = BigDecimal.valueOf(5, 1);
private static final BigDecimal EPS = BigDecimal.valueOf(1, 10_000);
private static BigDecimal nextHalfUp(double v) {
BigDecimal bv = new BigDecimal(v);
BigDecimal ulp = new BigDecimal(Math.ulp(v));
return bv.add(ulp.multiply(HALF));
}
private static BigDecimal nextHalfDown(double v) {
BigDecimal bv = new BigDecimal(v);
BigDecimal ulp = new BigDecimal(v - Math.nextDown(v));
return bv.subtract(ulp.multiply(HALF));
}
private static BigDecimal nextHalfUp(float v) {
BigDecimal bv = new BigDecimal(v);
BigDecimal ulp = new BigDecimal(Math.ulp(v));
return bv.add(ulp.multiply(HALF));
}
private static BigDecimal nextHalfDown(float v) {
BigDecimal bv = new BigDecimal(v);
BigDecimal ulp = new BigDecimal(v - Math.nextDown(v));
return bv.subtract(ulp.multiply(HALF));
}
private static BigDecimal nextHalfUp(Float16 v) {
BigDecimal bv = new BigDecimal(v.doubleValue());
BigDecimal ulp = new BigDecimal(Float16.ulp(v).doubleValue());
return bv.add(ulp.multiply(HALF));
}
private static BigDecimal nextHalfDown(Float16 v) {
BigDecimal bv = new BigDecimal(v.doubleValue());
BigDecimal ulp = new BigDecimal(v.doubleValue() - Float16.nextDown(v).doubleValue());
return bv.subtract(ulp.multiply(HALF));
}
private static String toDecHexString(double v) {
return v + " (" + Double.toHexString(v) + ")";
}
private static String toDecHexString(float v) {
return v + " (" + Float.toHexString(v) + ")";
}
private static String toDecHexString(Float16 v) {
return v + " (" + Float16.toHexString(v) + ")";
}
private static void checkDouble(BigDecimal bd, double exp) {
double res = bd.doubleValue();
if (exp != res ) {
String message = "Bad conversion: got " + toDecHexString(res) +
", expected " + toDecHexString(exp);
throw new RuntimeException(message);
}
}
private static void checkFloat(BigDecimal bv, float exp) {
float res = bv.floatValue();
if (exp != res ) {
String message = "Bad conversion: got " + toDecHexString(res) +
", expected " + toDecHexString(exp);
throw new RuntimeException(message);
}
}
private static void checkFloat16(BigDecimal bv, Float16 exp) {
Float16 res = Float16.valueOf(bv); // bv.float16Value();
if (exp.floatValue() != res.floatValue()) {
String message = "Bad conversion: got " + toDecHexString(res) +
", expected " + toDecHexString(exp);
throw new RuntimeException(message);
}
}
private static boolean isOdd(int n) {
return (n & 0x1) != 0;
}
private static void testDoubleValueNearMinValue() {
for (int n = 0; n < 100; ++n) {
BigDecimal b = nextHalfUp(n * Double.MIN_VALUE);
checkDouble(b, ((n + 1) / 2 * 2) * Double.MIN_VALUE);
checkDouble(b.subtract(EPS), n * Double.MIN_VALUE);
checkDouble(b.add(EPS), (n + 1) * Double.MIN_VALUE);
}
}
private static void testFloatValueNearMinValue() {
for (int n = 0; n < 100; ++n) {
BigDecimal b = nextHalfUp(n * Float.MIN_VALUE);
checkFloat(b, ((n + 1) / 2 * 2) * Float.MIN_VALUE);
checkFloat(b.subtract(EPS), n * Float.MIN_VALUE);
checkFloat(b.add(EPS), (n + 1) * Float.MIN_VALUE);
}
}
private static void testFloat16ValueNearMinValue() {
for (int n = 0; n < 100; ++n) {
BigDecimal b = nextHalfUp(Float16.multiply(Float16.valueOf(n), Float16.MIN_VALUE));
checkFloat16(b, Float16.multiply(Float16.valueOf((n + 1) / 2 * 2), Float16.MIN_VALUE));
checkFloat16(b.subtract(EPS), Float16.multiply(Float16.valueOf(n), Float16.MIN_VALUE));
checkFloat16(b.add(EPS), Float16.multiply(Float16.valueOf(n + 1), Float16.MIN_VALUE));
}
}
private static void testDoubleValueNearMinNormal() {
double v = Double.MIN_NORMAL;
for (int n = 0; n < 100; ++n) {
BigDecimal bv = nextHalfDown(v);
checkDouble(bv, isOdd(n) ? Math.nextDown(v) : v);
checkDouble(bv.subtract(EPS), Math.nextDown(v));
checkDouble(bv.add(EPS), v);
v = Math.nextDown(v);
}
v = Double.MIN_NORMAL;
for (int n = 0; n < 100; ++n) {
BigDecimal bv = nextHalfUp(v);
checkDouble(bv, isOdd(n) ? Math.nextUp(v) : v);
checkDouble(bv.subtract(EPS), v);
checkDouble(bv.add(EPS), Math.nextUp(v));
v = Math.nextUp(v);
}
}
private static void testFloatValueNearMinNormal() {
float v = Float.MIN_NORMAL;
for (int n = 0; n < 100; ++n) {
BigDecimal bv = nextHalfDown(v);
checkFloat(bv, isOdd(n) ? Math.nextDown(v) : v);
checkFloat(bv.subtract(EPS), Math.nextDown(v));
checkFloat(bv.add(EPS), v);
v = Math.nextDown(v);
}
v = Float.MIN_NORMAL;
for (int n = 0; n < 100; ++n) {
BigDecimal bv = nextHalfUp(v);
checkFloat(bv, isOdd(n) ? Math.nextUp(v) : v);
checkFloat(bv.subtract(EPS), v);
checkFloat(bv.add(EPS), Math.nextUp(v));
v = Math.nextUp(v);
}
}
private static void testFloat16ValueNearMinNormal() {
Float16 v = Float16.MIN_NORMAL;
for (int n = 0; n < 100; ++n) {
BigDecimal bv = nextHalfDown(v);
checkFloat16(bv, isOdd(n) ? Float16.nextDown(v) : v);
checkFloat16(bv.subtract(EPS), Float16.nextDown(v));
checkFloat16(bv.add(EPS), v);
v = Float16.nextDown(v);
}
v = Float16.MIN_NORMAL;
for (int n = 0; n < 100; ++n) {
BigDecimal bv = nextHalfUp(v);
checkFloat16(bv, isOdd(n) ? Float16.nextUp(v) : v);
checkFloat16(bv.subtract(EPS), v);
checkFloat16(bv.add(EPS), Float16.nextUp(v));
v = Float16.nextUp(v);
}
}
private static void testDoubleValueNearMaxValue() {
double v = Double.MAX_VALUE;
for (int n = 0; n < 100; ++n) {
BigDecimal bv = nextHalfDown(v);
checkDouble(bv, isOdd(n) ? v : Math.nextDown(v));
checkDouble(bv.subtract(EPS), Math.nextDown(v));
checkDouble(bv.add(EPS), v);
v = Math.nextDown(v);
}
BigDecimal bv = nextHalfUp(Double.MAX_VALUE);
checkDouble(bv, Double.POSITIVE_INFINITY);
checkDouble(bv.subtract(EPS), Double.MAX_VALUE);
checkDouble(bv.add(EPS), Double.POSITIVE_INFINITY);
}
private static void testFloatValueNearMaxValue() {
float v = Float.MAX_VALUE;
for (int n = 0; n < 100; ++n) {
BigDecimal bv = nextHalfDown(v);
checkFloat(bv, isOdd(n) ? v : Math.nextDown(v));
checkFloat(bv.subtract(EPS), Math.nextDown(v));
checkFloat(bv.add(EPS), v);
v = Math.nextDown(v);
}
BigDecimal bv = nextHalfUp(Float.MAX_VALUE);
checkFloat(bv, Float.POSITIVE_INFINITY);
checkFloat(bv.subtract(EPS), Float.MAX_VALUE);
checkFloat(bv.add(EPS), Float.POSITIVE_INFINITY);
}
private static void testFloat16ValueNearMaxValue() {
Float16 v = Float16.MAX_VALUE;
for (int n = 0; n < 100; ++n) {
BigDecimal bv = nextHalfDown(v);
checkFloat16(bv, isOdd(n) ? v : Float16.nextDown(v));
checkFloat16(bv.subtract(EPS), Float16.nextDown(v));
checkFloat16(bv.add(EPS), v);
v = Float16.nextDown(v);
}
BigDecimal bv = nextHalfUp(Float16.MAX_VALUE);
checkFloat16(bv, Float16.POSITIVE_INFINITY);
checkFloat16(bv.subtract(EPS), Float16.MAX_VALUE);
checkFloat16(bv.add(EPS), Float16.POSITIVE_INFINITY);
}
private static void testDoubleValueRandom() {
Random r = RandomFactory.getRandom();
for (int i = 0; i < 10_000; ++i) {
double v = r.nextDouble(-Double.MAX_VALUE, Double.MAX_VALUE);
checkDouble(new BigDecimal(v), v);
}
for (int i = 0; i < 10_000; ++i) {
double v = r.nextDouble(-1e9, 1e9);
checkDouble(new BigDecimal(v), v);
}
for (int i = 0; i < 10_000; ++i) {
double v = r.nextDouble(-1e6, 1e6);
checkDouble(new BigDecimal(v), v);
}
for (int i = 0; i < 10_000; ++i) {
double v = r.nextDouble(-1e-6, 1e-6);
checkDouble(new BigDecimal(v), v);
}
for (int i = 0; i < 10_000; ++i) {
double v = r.nextDouble(-1e-9, 1e-9);
checkDouble(new BigDecimal(v), v);
}
}
private static void testFloatValueRandom() {
Random r = RandomFactory.getRandom();
for (int i = 0; i < 10_000; ++i) {
float v = r.nextFloat(-Float.MAX_VALUE, Float.MAX_VALUE);
checkFloat(new BigDecimal(v), v);
}
for (int i = 0; i < 10_000; ++i) {
float v = r.nextFloat(-1e9f, 1e9f);
checkFloat(new BigDecimal(v), v);
}
for (int i = 0; i < 10_000; ++i) {
float v = r.nextFloat(-1e6f, 1e6f);
checkFloat(new BigDecimal(v), v);
}
for (int i = 0; i < 10_000; ++i) {
float v = r.nextFloat(-1e-6f, 1e-6f);
checkFloat(new BigDecimal(v), v);
}
for (int i = 0; i < 10_000; ++i) {
float v = r.nextFloat(-1e-9f, 1e-9f);
checkFloat(new BigDecimal(v), v);
}
}
private static void testFloat16ValueRandom() {
Random r = RandomFactory.getRandom();
for (int i = 0; i < 10_000; ++i) {
Float16 v = Float16.valueOf(r.nextFloat(-Float16.MAX_VALUE.floatValue(), Float16.MAX_VALUE.floatValue()));
checkFloat16(new BigDecimal(v.floatValue()), v);
}
for (int i = 0; i < 10_000; ++i) {
Float16 v = Float16.valueOf(r.nextFloat(-1e4f, 1e4f));
checkFloat16(new BigDecimal(v.floatValue()), v);
}
for (int i = 0; i < 10_000; ++i) {
Float16 v = Float16.valueOf(r.nextFloat(-1e3f, 1e3f));
checkFloat16(new BigDecimal(v.floatValue()), v);
}
for (int i = 0; i < 10_000; ++i) {
Float16 v = Float16.valueOf(r.nextFloat(-1e-3f, 1e-3f));
checkFloat16(new BigDecimal(v.floatValue()), v);
}
for (int i = 0; i < 10_000; ++i) {
Float16 v = Float16.valueOf(r.nextFloat(-1e-4f, 1e-4f));
checkFloat16(new BigDecimal(v.floatValue()), v);
}
}
private static void testDoubleValueExtremes() {
checkDouble(BigDecimal.valueOf(1, 1000), 0.0);
checkDouble(BigDecimal.valueOf(-1, 1000), -0.0);
checkDouble(BigDecimal.valueOf(1, -1000), Double.POSITIVE_INFINITY);
checkDouble(BigDecimal.valueOf(-1, -1000), Double.NEGATIVE_INFINITY);
}
private static void testFloatValueExtremes() {
checkFloat(BigDecimal.valueOf(1, 1000), 0.0f);
checkFloat(BigDecimal.valueOf(-1, 1000), -0.0f);
checkFloat(BigDecimal.valueOf(1, -1000), Float.POSITIVE_INFINITY);
checkFloat(BigDecimal.valueOf(-1, -1000), Float.NEGATIVE_INFINITY);
}
private static void testFloat16ValueExtremes() {
checkFloat16(BigDecimal.valueOf(1, 1000), Float16.valueOf(0.0f));
checkFloat16(BigDecimal.valueOf(-1, 1000), Float16.valueOf(-0.0f));
checkFloat16(BigDecimal.valueOf(1, -1000), Float16.POSITIVE_INFINITY);
checkFloat16(BigDecimal.valueOf(-1, -1000), Float16.NEGATIVE_INFINITY);
}
public static void main(String[] args) {
testDoubleValueNearMinValue();
testDoubleValueNearMinNormal();
testDoubleValueNearMaxValue();
testDoubleValueRandom();
testDoubleValueExtremes();
testFloatValueNearMinValue();
testFloatValueNearMinNormal();
testFloatValueNearMaxValue();
testFloatValueRandom();
testFloatValueExtremes();
testFloat16ValueNearMinValue();
testFloat16ValueNearMinNormal();
testFloat16ValueNearMaxValue();
testFloat16ValueRandom();
testFloat16ValueExtremes();
}
}

View file

@ -0,0 +1,91 @@
/*
* Copyright (c) 2009, 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.
*
* 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.
*/
/*
* @test
* @bug 1234567
* @summary Test BigDecimal.equals() method.
* @author xlu
*/
import java.math.*;
import static java.math.BigDecimal.*;
public class EqualsTests {
public static void main(String argv[]) {
int failures = 0;
BigDecimal[][] testValues = {
// The even index is supposed to return true for equals call and
// the odd index is supposed to return false, i.e. not equal.
{ZERO, ZERO},
{ONE, TEN},
{valueOf(Integer.MAX_VALUE), valueOf(Integer.MAX_VALUE)},
{valueOf(Long.MAX_VALUE), valueOf(-Long.MAX_VALUE)},
{valueOf(12345678), valueOf(12345678)},
{valueOf(123456789), valueOf(123456788)},
{new BigDecimal("123456789123456789123"),
new BigDecimal(new BigInteger("123456789123456789123"))},
{new BigDecimal("123456789123456789123"),
new BigDecimal(new BigInteger("123456789123456789124"))},
{valueOf(Long.MIN_VALUE), new BigDecimal("-9223372036854775808")},
{new BigDecimal("9223372036854775808"), valueOf(Long.MAX_VALUE)},
{valueOf(Math.round(Math.pow(2, 10))), new BigDecimal("1024")},
{new BigDecimal("1020"), valueOf(Math.pow(2, 11))},
{new BigDecimal(BigInteger.valueOf(2).pow(65)),
new BigDecimal("36893488147419103232")},
{new BigDecimal("36893488147419103231.81"),
new BigDecimal("36893488147419103231.811"),
}
};
boolean expected = Boolean.TRUE;
for (BigDecimal[] testValuePair : testValues) {
failures += equalsTest(testValuePair[0], testValuePair[1], expected);
expected = !expected;
}
if (failures > 0) {
throw new RuntimeException("Inccured " + failures +
" failures while testing equals.");
}
}
private static int equalsTest(BigDecimal l, BigDecimal r, boolean expected) {
boolean result = l.equals(r);
int failed = (result == expected) ? 0 : 1;
if (failed == 1) {
System.err.println(l + " .equals(" + r + ") => " + result +
"\n\tExpected " + expected);
}
return failed;
}
}

View file

@ -0,0 +1,188 @@
/*
* Copyright (c) 2005, 2018, 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.
*
* 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.
*/
/*
* @test
* @bug 6274390 7082971
* @summary Verify {float, double}Value methods work with condensed representation
* @run main FloatDoubleValueTests
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox -XX:AutoBoxCacheMax=20000 FloatDoubleValueTests
*/
import java.math.*;
public class FloatDoubleValueTests {
private static final long two2the24 = 1L<<23;
private static final long two2the53 = 1L<<52;
// Largest long that fits exactly in a float
private static final long maxFltLong = (long)(Integer.MAX_VALUE & ~(0xff));
// Largest long that fits exactly in a double
private static final long maxDblLong = Long.MAX_VALUE & ~(0x7ffL);
static void testDoubleValue0(long i, BigDecimal bd) {
if (bd.doubleValue() != i ||
bd.longValue() != i)
throw new RuntimeException("Unexpected equality failure for " +
i + "\t" + bd);
}
static void testFloatValue0(long i, BigDecimal bd) {
if (bd.floatValue() != i ||
bd.longValue() != i)
throw new RuntimeException("Unexpected equality failure for " +
i + "\t" + bd);
}
static void checkFloat(BigDecimal bd, float f) {
float fbd = bd.floatValue();
if (f != fbd ) {
String message = String.format("Bad conversion:"+
"got %g (%a)\texpected %g (%a)",
f, f, fbd, fbd);
throw new RuntimeException(message);
}
}
static void checkDouble(BigDecimal bd, double d) {
double dbd = bd.doubleValue();
if (d != dbd ) {
String message = String.format("Bad conversion:"+
"got %g (%a)\texpected %g (%a)",
d, d, dbd, dbd);
throw new RuntimeException(message);
}
}
// Test integral values that will convert exactly to both float
// and double.
static void testFloatDoubleValue() {
long longValues[] = {
Long.MIN_VALUE, // -2^63
0,
1,
2,
two2the24-1,
two2the24,
two2the24+1,
maxFltLong-1,
maxFltLong,
maxFltLong+1,
};
for(long i : longValues) {
BigDecimal bd1 = new BigDecimal(i);
BigDecimal bd2 = new BigDecimal(-i);
testDoubleValue0( i, bd1);
testDoubleValue0(-i, bd2);
testFloatValue0( i, bd1);
testFloatValue0(-i, bd2);
}
}
static void testDoubleValue() {
long longValues[] = {
Integer.MAX_VALUE-1,
Integer.MAX_VALUE,
(long)Integer.MAX_VALUE+1,
two2the53-1,
two2the53,
two2the53+1,
maxDblLong,
};
// Test integral values that will convert exactly to double
// but not float.
for(long i : longValues) {
BigDecimal bd1 = new BigDecimal(i);
BigDecimal bd2 = new BigDecimal(-i);
testDoubleValue0( i, bd1);
testDoubleValue0(-i, bd2);
checkFloat(bd1, (float)i);
checkFloat(bd2, -(float)i);
}
// Now check values that should not convert the same in double
for(long i = maxDblLong; i < Long.MAX_VALUE; i++) {
BigDecimal bd1 = new BigDecimal(i);
BigDecimal bd2 = new BigDecimal(-i);
checkDouble(bd1, (double)i);
checkDouble(bd2, -(double)i);
checkFloat(bd1, (float)i);
checkFloat(bd2, -(float)i);
}
checkDouble(new BigDecimal(Long.MIN_VALUE), (double)Long.MIN_VALUE);
checkDouble(new BigDecimal(Long.MAX_VALUE), (double)Long.MAX_VALUE);
}
static void testFloatValue() {
// Now check values that should not convert the same in float
for(long i = maxFltLong; i <= Integer.MAX_VALUE; i++) {
BigDecimal bd1 = new BigDecimal(i);
BigDecimal bd2 = new BigDecimal(-i);
checkFloat(bd1, (float)i);
checkFloat(bd2, -(float)i);
testDoubleValue0( i, bd1);
testDoubleValue0(-i, bd2);
}
}
static void testFloatValue1() {
checkFloat(new BigDecimal("85070591730234615847396907784232501249"), 8.507059e+37f);
checkFloat(new BigDecimal("7784232501249e12"), 7.7842326e24f);
checkFloat(new BigDecimal("907784232501249e-12"),907.78424f);
checkFloat(new BigDecimal("7784e8"),7.7839997e11f);
checkFloat(new BigDecimal("9077e-8"),9.077e-5f);
}
static void testDoubleValue1() {
checkDouble(new BigDecimal("85070591730234615847396907784232501249"), 8.507059173023462e37);
checkDouble(new BigDecimal("7784232501249e12"), 7.784232501249e24);
checkDouble(new BigDecimal("907784232501249e-12"), 907.784232501249);
checkDouble(new BigDecimal("7784e8"), 7.784e11);
checkDouble(new BigDecimal("9077e-8"), 9.077e-5);
}
public static void main(String[] args) throws Exception {
testFloatDoubleValue();
testDoubleValue();
testFloatValue();
testFloatValue1();
testDoubleValue1();
}
}

View file

@ -0,0 +1,120 @@
/*
* Copyright (c) 2019, 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.
*
* 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.
*/
/**
* @test
* @bug 8211936
* @summary Tests of BigDecimal.intValueExact
*/
import java.math.*;
import java.util.List;
import java.util.Map;
import static java.util.Map.entry;
public class IntValueExactTests {
public static void main(String... args) {
int failures = 0;
failures += intValueExactSuccessful();
failures += intValueExactExceptional();
if (failures > 0) {
throw new RuntimeException("Incurred " + failures +
" failures while testing intValueExact.");
}
}
private static int simpleIntValueExact(BigDecimal bd) {
return bd.toBigIntegerExact().intValue();
}
private static int intValueExactSuccessful() {
int failures = 0;
// Strings used to create BigDecimal instances on which invoking
// intValueExact() will succeed.
Map<BigDecimal, Integer> successCases =
Map.ofEntries(entry(new BigDecimal("2147483647"), Integer.MAX_VALUE), // 2^31 -1
entry(new BigDecimal("2147483647.0"), Integer.MAX_VALUE),
entry(new BigDecimal("2147483647.00"), Integer.MAX_VALUE),
entry(new BigDecimal("-2147483648"), Integer.MIN_VALUE), // -2^31
entry(new BigDecimal("-2147483648.0"), Integer.MIN_VALUE),
entry(new BigDecimal("-2147483648.00"),Integer.MIN_VALUE),
entry(new BigDecimal("1e0"), 1),
entry(new BigDecimal(BigInteger.ONE, -9), 1_000_000_000),
entry(new BigDecimal("0e13"), 0), // Fast path zero
entry(new BigDecimal("0e32"), 0),
entry(new BigDecimal("0e512"), 0),
entry(new BigDecimal("10.000000000000000000000000000000000"), 10));
for (var testCase : successCases.entrySet()) {
BigDecimal bd = testCase.getKey();
int expected = testCase.getValue();
try {
int intValueExact = bd.intValueExact();
if (expected != intValueExact ||
intValueExact != simpleIntValueExact(bd)) {
failures++;
System.err.println("Unexpected intValueExact result " + intValueExact +
" on " + bd);
}
} catch (Exception e) {
failures++;
System.err.println("Error on " + bd + "\tException message:" + e.getMessage());
}
}
return failures;
}
private static int intValueExactExceptional() {
int failures = 0;
List<BigDecimal> exceptionalCases =
List.of(new BigDecimal("2147483648"), // Integer.MAX_VALUE + 1
new BigDecimal("2147483648.0"),
new BigDecimal("2147483648.00"),
new BigDecimal("-2147483649"), // Integer.MIN_VALUE - 1
new BigDecimal("-2147483649.1"),
new BigDecimal("-2147483649.01"),
new BigDecimal("9999999999999999999999999999999"),
new BigDecimal("10000000000000000000000000000000"),
new BigDecimal("0.99"),
new BigDecimal("0.999999999999999999999"));
for (BigDecimal bd : exceptionalCases) {
try {
int intValueExact = bd.intValueExact();
failures++;
System.err.println("Unexpected non-exceptional intValueExact on " + bd);
} catch (ArithmeticException e) {
// Success;
}
}
return failures;
}
}

View file

@ -0,0 +1,352 @@
/*
* Copyright (c) 2003, 2025, 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.
*
* 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.
*/
/*
* @test
* @bug 4904082 4917089 6337226 6378503
* @summary Tests that integral division and related methods return the proper result and scale.
*/
import java.math.*;
public class IntegralDivisionTests {
static int dividetoIntegralValueTests() {
int failures = 0;
// Exact integer quotient should have the same results from
// the exact divide and dividetoIntegralValue
// Rounded results
BigDecimal [][] moreTestCases = {
{new BigDecimal("11003"), new BigDecimal("10"), new BigDecimal("1100")},
{new BigDecimal("11003"), new BigDecimal("1e1"), new BigDecimal("1100.0")},
{new BigDecimal("1e9"), new BigDecimal("1"), new BigDecimal("1e9")},
{new BigDecimal("1e9"), new BigDecimal("1.00"), new BigDecimal("1e9")},
{new BigDecimal("1e9"), new BigDecimal("0.1"), new BigDecimal("1e10")},
{new BigDecimal("10e8"), new BigDecimal("0.1"), new BigDecimal("10e9")},
{new BigDecimal("400e1"), new BigDecimal("5"), new BigDecimal("80e1")},
{new BigDecimal("400e1"), new BigDecimal("4.999999999"), new BigDecimal("8e2")},
{new BigDecimal("40e2"), new BigDecimal("5"), new BigDecimal("8e2")},
{BigDecimal.valueOf(1, Integer.MIN_VALUE),
BigDecimal.valueOf(1, -(Integer.MAX_VALUE & 0x7fffff00)),
BigDecimal.valueOf(1, -256)},
};
for(BigDecimal [] testCase: moreTestCases) {
BigDecimal quotient;
if (! (quotient=testCase[0].divideToIntegralValue(testCase[1])).equals(testCase[2]) ){
failures++;
// BigDecimal exact = testCase[0].divide(testCase[1]);
System.err.println();
System.err.println("dividend = " + testCase[0] + " scale = " + testCase[0].scale());
System.err.println("divisor = " + testCase[1] + " scale = " + testCase[1].scale());
System.err.println("quotient = " + quotient + " scale = " + quotient.scale());
System.err.println("expected = " + testCase[2] + " scale = " + testCase[2].scale());
// System.err.println("exact = " + exact + " scale = " + exact.scale());
}
}
return failures;
}
static int dividetoIntegralValueRoundedTests() {
int failures = 0;
BigDecimal dividend = new BigDecimal("11003");
BigDecimal divisor = new BigDecimal("10");
BigDecimal [] quotients = { // Expected results with precision =
new BigDecimal("1100"), // 0
null, // 1
new BigDecimal("11e2"), // 2
new BigDecimal("110e1"), // 3
new BigDecimal("1100"), // 4
};
failures += divideContextTestPrecs(dividend, divisor, quotients);
dividend = new BigDecimal("11003");
divisor = new BigDecimal("1e1");
BigDecimal [] quotients2 = { // Expected results with precision =
new BigDecimal("1100.0"), // 0
null, // 1
new BigDecimal("11e2"), // 2
new BigDecimal("110e1"), // 3
new BigDecimal("1100"), // 4
new BigDecimal("1100.0"), // 5
};
failures += divideContextTestPrecs(dividend, divisor, quotients2);
dividend = new BigDecimal("1230000");
divisor = new BigDecimal("100");
BigDecimal [] quotients3 = { // Expected results with precision =
new BigDecimal("12300"), // 0
null, // 1
null, // 2
new BigDecimal("123e2"), // 3
new BigDecimal("1230e1"), // 4
new BigDecimal("12300"), // 5
};
failures += divideContextTestPrecs(dividend, divisor, quotients3);
dividend = new BigDecimal("33");
divisor = new BigDecimal("3");
BigDecimal [] quotients4 = { // Expected results with precision =
new BigDecimal("11"), // 0
null, // 1
new BigDecimal("11"), // 2
new BigDecimal("11"), // 3
};
failures += divideContextTestPrecs(dividend, divisor, quotients4);
dividend = new BigDecimal("34");
divisor = new BigDecimal("3");
BigDecimal [] quotients5 = { // Expected results with precision =
new BigDecimal("11"), // 0
null, // 1
new BigDecimal("11"), // 2
new BigDecimal("11"), // 3
};
failures += divideContextTestPrecs(dividend, divisor, quotients5);
return failures;
}
static int divideContextTestPrecs(BigDecimal dividend,
BigDecimal divisor,
BigDecimal[] quotients)
{
int failures = 0;
for(int i = 0; i < quotients.length; i++) {
BigDecimal result = null;
BigDecimal quotient = quotients[i];
try {
result = dividend.divideToIntegralValue(divisor,
new MathContext(i, RoundingMode.DOWN));
} catch (ArithmeticException e) {
if (quotient != null) {
failures++;
System.err.println();
System.err.println("Unexpected exception:");
System.err.println("dividend = " + dividend + " scale = " + dividend.scale());
System.err.println("divisor = " + divisor + " scale = " + divisor.scale());
System.err.println("expected = " + quotient + " scale = " + quotient.scale());
}
}
if (quotient != null) {
if (! result.equals(quotient)) {
failures++;
System.err.println();
System.err.println("Unexpected result:");
System.err.println("dividend = " + dividend + " scale = " + dividend.scale());
System.err.println("divisor = " + divisor + " scale = " + divisor.scale());
System.err.println("quotient = " + result + " scale = " + result.scale());
System.err.println("expected = " + quotient + " scale = " + quotient.scale());
System.err.println("precision = " + i);
}
} else {
if (result != null) {
failures++;
System.err.println();
System.err.println("Unexpected unexceptional result:");
System.err.println("dividend = " + dividend + " scale = " + dividend.scale());
System.err.println("divisor = " + divisor + " scale = " + divisor.scale());
System.err.println("quotient = " + result + " scale = " + result.scale());
System.err.println("precision = " + i);
}
}
}
return failures;
}
static int divideContextTests(BigDecimal dividend,
BigDecimal divisor,
BigDecimal expected,
MathContext mc) {
int failures = 0;
failures += divideContextTest(dividend, divisor, expected, mc);
failures += divideContextTest(dividend.negate(), divisor.negate(), expected, mc);
if (expected != null) {
failures += divideContextTest(dividend.negate(), divisor, expected.negate(), mc);
failures += divideContextTest(dividend, divisor.negate(), expected.negate(), mc);
}
return failures;
}
static int divideContextTest(BigDecimal dividend,
BigDecimal divisor,
BigDecimal expected,
MathContext mc)
{
int failures = 0;
BigDecimal result = null;
try {
result = dividend.divideToIntegralValue(divisor, mc);
} catch (ArithmeticException e) {
if (expected != null) {
failures++;
System.err.println();
System.err.println("Unexpected exception:");
System.err.println("dividend = " + dividend + " scale = " + dividend.scale());
System.err.println("divisor = " + divisor + " scale = " + divisor.scale());
System.err.println("expected = " + expected + " scale = " + expected.scale());
System.err.println("MathContext = " + mc);
}
}
if (expected != null) {
if (! result.equals(expected)) {
failures++;
System.err.println();
System.err.println("Unexpected result:");
System.err.println("dividend = " + dividend + " scale = " + dividend.scale());
System.err.println("divisor = " + divisor + " scale = " + divisor.scale());
System.err.println("expected = " + expected + " scale = " + expected.scale());
System.err.println("result = " + result + " scale = " + result.scale());
System.err.println("MathContext = " + mc);
}
} else {
if (result != null) {
failures++;
System.err.println();
System.err.println("Unexpected unexceptional result:");
System.err.println("dividend = " + dividend + " scale = " + dividend.scale());
System.err.println("divisor = " + divisor + " scale = " + divisor.scale());
System.err.println("quotient = " + result + " scale = " + result.scale());
System.err.println("MathConext = " + mc);
}
}
return failures;
}
static int dividetoIntegralValueScalingTests() {
int failures = 0;
BigDecimal dividend = new BigDecimal("123456789000");
BigDecimal divisor = BigDecimal.ONE;
BigDecimal expected = new BigDecimal("123456789e3");
MathContext mc = new MathContext(9,RoundingMode.DOWN);
failures += divideContextTests(dividend, divisor, expected, mc);
// 100/3 = 33 remainder 1
int [] precisions = {0, 2, 3, 4};
dividend = new BigDecimal(100);
divisor = new BigDecimal(3);
expected = new BigDecimal(33);
for(RoundingMode rm: RoundingMode.values())
for(int precision: precisions) {
failures += divideContextTests(dividend, divisor, expected,
new MathContext(precision, rm));
}
// 123000/10 = 12300 remainder 0
dividend = new BigDecimal(123000);
divisor = new BigDecimal(10);
int[] precisions1 = {0, 1, 2, 3, 4, 5};
BigDecimal[] expected1 = {
new BigDecimal("12300"),
null,
null,
new BigDecimal("123e2"),
new BigDecimal("1230e1"),
new BigDecimal("12300"),
};
for(RoundingMode rm: RoundingMode.values())
for(int i = 0; i < precisions1.length; i++) {
failures += divideContextTests(dividend, divisor,
expected1[i],
new MathContext(precisions1[i], rm));
}
// 123e3/10 = 123e2 remainder 0
dividend = new BigDecimal("123e3");
divisor = new BigDecimal(10);
int[] precisions2 = {0, 1, 2, 3, 4, 5};
BigDecimal[] expected2 = {
new BigDecimal("123e2"),
null,
null,
new BigDecimal("123e2"),
new BigDecimal("123e2"),
new BigDecimal("123e2"),
};
for(RoundingMode rm: RoundingMode.values())
for(int i = 0; i < precisions2.length; i++) {
failures += divideContextTests(dividend, divisor,
expected2[i],
new MathContext(precisions2[i], rm));
}
// 123000/1e1 = 12300.0 remainder 0
dividend = new BigDecimal("123000");
divisor = new BigDecimal("1e1");
int[] precisions3 = {0, 1, 2, 3, 4, 5, 6};
BigDecimal[] expected3 = {
new BigDecimal("12300.0"),
null,
null,
new BigDecimal("123e2"),
new BigDecimal("1230e1"),
new BigDecimal("12300"),
new BigDecimal("12300.0"),
};
for(RoundingMode rm: RoundingMode.values())
for(int i = 0; i < precisions3.length; i++) {
failures += divideContextTests(dividend, divisor,
expected3[i],
new MathContext(precisions3[i], rm));
}
return failures;
}
public static void main(String argv[]) {
int failures = 0;
failures += dividetoIntegralValueTests();
failures += dividetoIntegralValueRoundedTests();
failures += dividetoIntegralValueScalingTests();
if (failures > 0) {
System.err.println("Encountered " + failures +
" failures while testing integral division.");
throw new RuntimeException();
}
}
}

View file

@ -0,0 +1,241 @@
/*
* Copyright (c) 2019, 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.
*
* 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.
*/
/*
* @test
* @bug 8211936
* @summary Tests of BigDecimal.intValue() and BigDecimal.longValue()
*/
import java.math.BigDecimal;
import java.util.Map;
public class IntegralValueTests {
public static void main(String... args) {
int failures =
integralValuesTest(INT_VALUES, true) +
integralValuesTest(LONG_VALUES, false);
if (failures != 0) {
throw new RuntimeException
("Incurred " + failures + " failures for {int,long}Value().");
}
}
private static final Map<BigDecimal, Number> INT_VALUES =
Map.ofEntries(
// 2**31 - 1
Map.entry(new BigDecimal("2147483647"), Integer.MAX_VALUE),
Map.entry(new BigDecimal("2147483647.0"), Integer.MAX_VALUE),
Map.entry(new BigDecimal("2147483647.00"), Integer.MAX_VALUE),
Map.entry(new BigDecimal("-2147483647"), -Integer.MAX_VALUE),
Map.entry(new BigDecimal("-2147483647.0"), -Integer.MAX_VALUE),
// -2**31
Map.entry(new BigDecimal("-2147483648"), Integer.MIN_VALUE),
Map.entry(new BigDecimal("-2147483648.1"), Integer.MIN_VALUE),
Map.entry(new BigDecimal("-2147483648.01"), Integer.MIN_VALUE),
// -2**31 + 1 truncation to 2**31 - 1
Map.entry(new BigDecimal("-2147483649"), Integer.MAX_VALUE),
// 2**64 - 1 truncation to 1
Map.entry(new BigDecimal("4294967295"), -1),
// 2**64 truncation to 0
Map.entry(new BigDecimal("4294967296"), 0),
// Fast path truncation to 0
Map.entry(new BigDecimal("1e32"), 0),
// Slow path truncation to -2**31
Map.entry(new BigDecimal("1e31"), Integer.MIN_VALUE),
// Slow path
Map.entry(new BigDecimal("1e0"), 1),
// Fast path round to 0
Map.entry(new BigDecimal("9e-1"), 0),
// Some random values
Map.entry(new BigDecimal("900e-1"), 90), // Increasing negative exponents
Map.entry(new BigDecimal("900e-2"), 9),
Map.entry(new BigDecimal("900e-3"), 0),
// Fast path round to 0
Map.entry(new BigDecimal("123456789e-9"), 0),
// Slow path round to 1
Map.entry(new BigDecimal("123456789e-8"), 1),
// Increasing positive exponents
Map.entry(new BigDecimal("10000001e1"), 100000010),
Map.entry(new BigDecimal("10000001e10"), -1315576832),
Map.entry(new BigDecimal("10000001e100"), 0),
Map.entry(new BigDecimal("10000001e1000"), 0),
Map.entry(new BigDecimal("10000001e10000"), 0),
Map.entry(new BigDecimal("10000001e100000"), 0),
Map.entry(new BigDecimal("10000001e1000000"), 0),
Map.entry(new BigDecimal("10000001e10000000"), 0),
Map.entry(new BigDecimal("10000001e100000000"), 0),
Map.entry(new BigDecimal("10000001e1000000000"), 0),
// Increasing negative exponents
Map.entry(new BigDecimal("10000001e-1"), 1000000),
Map.entry(new BigDecimal("10000001e-10"), 0),
Map.entry(new BigDecimal("10000001e-100"), 0),
Map.entry(new BigDecimal("10000001e-1000"), 0),
Map.entry(new BigDecimal("10000001e-10000"), 0),
Map.entry(new BigDecimal("10000001e-100000"), 0),
Map.entry(new BigDecimal("10000001e-1000000"), 0),
Map.entry(new BigDecimal("10000001e-10000000"), 0),
Map.entry(new BigDecimal("10000001e-100000000"), 0),
Map.entry(new BigDecimal("10000001e-1000000000"), 0),
// Currency calculation to 4 places
Map.entry(new BigDecimal("12345.0001"), 12345),
Map.entry(new BigDecimal("12345.9999"), 12345),
Map.entry(new BigDecimal("-12345.0001"), -12345),
Map.entry(new BigDecimal("-12345.9999"), -12345));
private static final Map<BigDecimal, Number> LONG_VALUES =
Map.ofEntries(
// 2**63 - 1
Map.entry(new BigDecimal("9223372036854775807"), Long.MAX_VALUE),
Map.entry(new BigDecimal("9223372036854775807.0"), Long.MAX_VALUE),
Map.entry(new BigDecimal("9223372036854775807.00"), Long.MAX_VALUE),
// 2**63 truncation to -2**63
Map.entry(new BigDecimal("-9223372036854775808"), Long.MIN_VALUE),
Map.entry(new BigDecimal("-9223372036854775808.1"), Long.MIN_VALUE),
Map.entry(new BigDecimal("-9223372036854775808.01"), Long.MIN_VALUE),
// -2**63 + 1 truncation to 2**63 - 1
Map.entry(new BigDecimal("-9223372036854775809"), 9223372036854775807L),
// 2**64 - 1 truncation to -1
Map.entry(new BigDecimal("18446744073709551615"), -1L),
// 2**64 truncation to 0
Map.entry(new BigDecimal("18446744073709551616"), 0L),
// Slow path truncation to -2**63
Map.entry(new BigDecimal("1e63"), -9223372036854775808L),
Map.entry(new BigDecimal("-1e63"), -9223372036854775808L),
// Fast path with larger magnitude scale
Map.entry(new BigDecimal("1e64"), 0L),
Map.entry(new BigDecimal("-1e64"), 0L),
Map.entry(new BigDecimal("1e65"), 0L),
Map.entry(new BigDecimal("-1e65"), 0L),
// Slow path
Map.entry(new BigDecimal("1e0"), 1L),
// Fast path round to 0
Map.entry(new BigDecimal("9e-1"), 0L),
// Some random values
Map.entry(new BigDecimal("900e-1"), 90L), // Increasing negative exponents
Map.entry(new BigDecimal("900e-2"), 9L),
Map.entry(new BigDecimal("900e-3"), 0L),
// Fast path round to 0
Map.entry(new BigDecimal("123456789e-9"), 0L),
// Slow path round to 1
Map.entry(new BigDecimal("123456789e-8"), 1L),
// Increasing positive exponents
Map.entry(new BigDecimal("10000001e1"), 100000010L),
Map.entry(new BigDecimal("10000001e10"), 100000010000000000L),
Map.entry(new BigDecimal("10000001e100"), 0L),
Map.entry(new BigDecimal("10000001e1000"), 0L),
Map.entry(new BigDecimal("10000001e10000"), 0L),
Map.entry(new BigDecimal("10000001e100000"), 0L),
Map.entry(new BigDecimal("10000001e1000000"), 0L),
Map.entry(new BigDecimal("10000001e10000000"), 0L),
Map.entry(new BigDecimal("10000001e100000000"), 0L),
Map.entry(new BigDecimal("10000001e1000000000"), 0L),
// Increasing negative exponents
Map.entry(new BigDecimal("10000001e-1"), 1000000L),
Map.entry(new BigDecimal("10000001e-10"), 0L),
Map.entry(new BigDecimal("10000001e-100"), 0L),
Map.entry(new BigDecimal("10000001e-1000"), 0L),
Map.entry(new BigDecimal("10000001e-10000"), 0L),
Map.entry(new BigDecimal("10000001e-100000"), 0L),
Map.entry(new BigDecimal("10000001e-1000000"), 0L),
Map.entry(new BigDecimal("10000001e-10000000"), 0L),
Map.entry(new BigDecimal("10000001e-100000000"), 0L),
Map.entry(new BigDecimal("10000001e-1000000000"), 0L),
// Currency calculation to 4 places
Map.entry(new BigDecimal("12345.0001"), 12345L),
Map.entry(new BigDecimal("12345.9999"), 12345L),
Map.entry(new BigDecimal("-12345.0001"), -12345L),
Map.entry(new BigDecimal("-12345.9999"), -12345L));
private static int integralValuesTest(Map<BigDecimal, Number> v, boolean isInt) {
System.err.format("Testing %s%n", isInt ? "Integer" : "Long");
int failures = 0;
for (var testCase : v.entrySet()) {
BigDecimal bd = testCase.getKey();
Number expected = testCase.getValue();
try {
if (isInt) {
int intValue = bd.intValue();
if (intValue != (int)expected) {
failures += reportError(bd, expected, intValue, isInt);
}
} else {
long longValue = bd.longValue();
if (longValue != (long)expected) {
failures += reportError(bd, expected, longValue, isInt);
}
}
} catch (Exception e) {
failures++;
System.err.format("Unexpected exception %s for %s%n",
e, bd.toString());
}
}
return failures;
}
private static int reportError(BigDecimal bd, Number expected, long longValue, boolean isInt) {
System.err.format("For %s, scale=%d, expected %d, actual %d, simple %d%n",
bd.toString(), bd.scale(),
(isInt ? (Integer) expected : (Long) expected ),
longValue,
(isInt ? simpleIntValue(bd): simpleLongValue(bd) ));
return 1;
}
private static long simpleLongValue(BigDecimal bd) {
return bd.toBigInteger().longValue();
}
private static int simpleIntValue(BigDecimal bd) {
return bd.toBigInteger().intValue();
}
}

View file

@ -0,0 +1,144 @@
/*
* Copyright (c) 2005, 2023, 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.
*
* 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.
*/
/**
* @test
* @bug 6806261 8211936 8305343
* @summary Tests of BigDecimal.longValueExact
*/
import java.math.*;
import java.util.List;
import java.util.Map;
import static java.util.Map.entry;
public class LongValueExactTests {
public static void main(String... args) {
int failures = 0;
failures += longValueExactSuccessful();
failures += longValueExactExceptional();
failures += longValueExactExceptional8305343();
if (failures > 0) {
throw new RuntimeException("Incurred " + failures +
" failures while testing longValueExact.");
}
}
private static long simpleLongValueExact(BigDecimal bd) {
return bd.toBigIntegerExact().longValue();
}
private static int longValueExactSuccessful() {
int failures = 0;
// Strings used to create BigDecimal instances on which invoking
// longValueExact() will succeed.
Map<BigDecimal, Long> successCases =
Map.ofEntries(entry(new BigDecimal("9223372036854775807"), Long.MAX_VALUE), // 2^63 -1
entry(new BigDecimal("9223372036854775807.0"), Long.MAX_VALUE),
entry(new BigDecimal("9223372036854775807.00"), Long.MAX_VALUE),
entry(new BigDecimal("-9223372036854775808"), Long.MIN_VALUE), // -2^63
entry(new BigDecimal("-9223372036854775808.0"), Long.MIN_VALUE),
entry(new BigDecimal("-9223372036854775808.00"),Long.MIN_VALUE),
entry(new BigDecimal("1e0"), 1L),
entry(new BigDecimal(BigInteger.ONE, -18), 1_000_000_000_000_000_000L),
entry(new BigDecimal("0e13"), 0L), // Fast path zero
entry(new BigDecimal("0e64"), 0L),
entry(new BigDecimal("0e1024"), 0L),
entry(new BigDecimal("10.000000000000000000000000000000000"), 10L));
for (var testCase : successCases.entrySet()) {
BigDecimal bd = testCase.getKey();
long expected = testCase.getValue();
try {
long longValueExact = bd.longValueExact();
if (expected != longValueExact ||
longValueExact != simpleLongValueExact(bd)) {
failures++;
System.err.println("Unexpected longValueExact result " + longValueExact +
" on " + bd);
}
} catch (Exception e) {
failures++;
System.err.println("Error on " + bd + "\tException message:" + e.getMessage());
}
}
return failures;
}
private static int longValueExactExceptional() {
int failures = 0;
List<BigDecimal> exceptionalCases =
List.of(new BigDecimal("9223372036854775808"), // Long.MAX_VALUE + 1
new BigDecimal("9223372036854775808.0"),
new BigDecimal("9223372036854775808.00"),
new BigDecimal("-9223372036854775809"), // Long.MIN_VALUE - 1
new BigDecimal("-9223372036854775808.1"),
new BigDecimal("-9223372036854775808.01"),
new BigDecimal("9999999999999999999"),
new BigDecimal("10000000000000000000"),
new BigDecimal("0.99"),
new BigDecimal("0.999999999999999999999"));
for (BigDecimal bd : exceptionalCases) {
try {
long longValueExact = bd.longValueExact();
failures++;
System.err.println("Unexpected non-exceptional longValueExact on " + bd);
} catch (ArithmeticException e) {
// Success;
}
}
return failures;
}
private static int longValueExactExceptional8305343() {
int failures = 0;
List<BigDecimal> exceptionalCases =
List.of(new BigDecimal("1e" + (Integer.MAX_VALUE - 1)),
new BigDecimal("1e" + (Integer.MAX_VALUE))
);
for (BigDecimal bd : exceptionalCases) {
try {
bd.longValueExact();
failures++;
System.err.println("Unexpected non-exceptional longValueExact on " + bd);
} catch (ArithmeticException e) {
if (!e.getMessage().toLowerCase().contains("overflow")) {
failures++;
System.err.println("Unexpected non-exceptional longValueExact on " + bd);
}
}
}
return failures;
}
}

View file

@ -0,0 +1,106 @@
/*
* Copyright (c) 2022, 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.
*
* 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.
*/
/*
* @test
* @bug 8289260
*/
import java.math.BigDecimal;
public class MovePointTests {
public static void main(String argv[]) {
BigDecimal bd;
bd = BigDecimal.valueOf(1, -3);
checkNotIdentical(bd, bd.movePointLeft(0));
checkNotIdentical(bd, bd.movePointRight(0));
bd = BigDecimal.valueOf(1, 0);
checkIdentical(bd, bd.movePointLeft(0));
checkIdentical(bd, bd.movePointRight(0));
bd = BigDecimal.valueOf(1, 3);
checkIdentical(bd, bd.movePointLeft(0));
checkIdentical(bd, bd.movePointRight(0));
bd = BigDecimal.valueOf(1, -3);
checkNotEquals(bd, bd.movePointLeft(1));
checkNotEquals(bd, bd.movePointLeft(-1));
checkNotEquals(bd, bd.movePointRight(1));
checkNotEquals(bd, bd.movePointRight(-1));
bd = BigDecimal.valueOf(1, 0);
checkNotEquals(bd, bd.movePointLeft(1));
checkNotEquals(bd, bd.movePointLeft(-1));
checkNotEquals(bd, bd.movePointRight(1));
checkNotEquals(bd, bd.movePointRight(-1));
bd = BigDecimal.valueOf(1, 3);
checkNotEquals(bd, bd.movePointLeft(1));
checkNotEquals(bd, bd.movePointLeft(-1));
checkNotEquals(bd, bd.movePointRight(1));
checkNotEquals(bd, bd.movePointRight(-1));
bd = BigDecimal.valueOf(1, -3);
checkNotEquals(bd, bd.movePointLeft(10));
checkNotEquals(bd, bd.movePointLeft(-10));
checkNotEquals(bd, bd.movePointRight(10));
checkNotEquals(bd, bd.movePointRight(-10));
bd = BigDecimal.valueOf(1, 0);
checkNotEquals(bd, bd.movePointLeft(10));
checkNotEquals(bd, bd.movePointLeft(-10));
checkNotEquals(bd, bd.movePointRight(10));
checkNotEquals(bd, bd.movePointRight(-10));
bd = BigDecimal.valueOf(1, 3);
checkNotEquals(bd, bd.movePointLeft(10));
checkNotEquals(bd, bd.movePointLeft(-10));
checkNotEquals(bd, bd.movePointRight(10));
checkNotEquals(bd, bd.movePointRight(-10));
}
private static void checkIdentical(BigDecimal bd, BigDecimal res) {
if (res != bd) { // intentionally !=
throw new RuntimeException("Unexpected result " +
bd + " != " + res);
}
}
private static void checkNotIdentical(BigDecimal bd, BigDecimal res) {
if (res == bd) { // intentionally ==
throw new RuntimeException("Unexpected result " +
bd + " == " + res);
}
}
private static void checkNotEquals(BigDecimal bd, BigDecimal res) {
if (res.equals(bd)) {
throw new RuntimeException("Unexpected result " +
bd + ".equals(" + res + ")");
}
}
}

View file

@ -0,0 +1,98 @@
/*
* Copyright (c) 2006, 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.
*
* 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.
*/
/*
* @test
* @bug 6850606
* @summary Test BigDecimal.multiply(BigDecimal)
* @author xlu
*/
import java.math.*;
import static java.math.BigDecimal.*;
public class MultiplyTests {
private static int multiplyTests() {
int failures = 0;
BigDecimal[] bd1 = {
new BigDecimal("123456789"),
new BigDecimal("1234567898"),
new BigDecimal("12345678987")
};
BigDecimal[] bd2 = {
new BigDecimal("987654321"),
new BigDecimal("8987654321"),
new BigDecimal("78987654321")
};
// Two dimensonal array recording bd1[i] * bd2[j] &
// 0 <= i <= 2 && 0 <= j <= 2;
BigDecimal[][] expectedResults = {
{new BigDecimal("121932631112635269"),
new BigDecimal("1109586943112635269"),
new BigDecimal("9751562173112635269")
},
{ new BigDecimal("1219326319027587258"),
new BigDecimal("11095869503027587258"),
new BigDecimal("97515622363027587258")
},
{ new BigDecimal("12193263197189452827"),
new BigDecimal("110958695093189452827"),
new BigDecimal("975156224183189452827")
}
};
for (int i = 0; i < bd1.length; i++) {
for (int j = 0; j < bd2.length; j++) {
if (!bd1[i].multiply(bd2[j]).equals(expectedResults[i][j])) {
failures++;
}
}
}
BigDecimal x = BigDecimal.valueOf(8L, 1);
BigDecimal xPower = BigDecimal.valueOf(-1L);
try {
for (int i = 0; i < 100; i++) {
xPower = xPower.multiply(x);
}
} catch (Exception ex) {
failures++;
}
return failures;
}
public static void main(String[] args) {
int failures = 0;
failures += multiplyTests();
if (failures > 0) {
throw new RuntimeException("Incurred " + failures +
" failures while testing multiply.");
}
}
}

View file

@ -0,0 +1,110 @@
/*
* Copyright (c) 2005, 2025, 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.
*
* 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.
*/
/*
* @test
* @bug 6325535
* @summary Test for the rounding behavior of negate(MathContext)
*/
import java.math.*;
public class NegateTests {
static BigDecimal negateThenRound(BigDecimal bd, MathContext mc) {
return bd.negate().plus(mc);
}
static BigDecimal absThenRound(BigDecimal bd, MathContext mc) {
return bd.abs().plus(mc);
}
static int negateTest(BigDecimal[][] testCases, MathContext mc) {
int failures = 0;
for (BigDecimal [] testCase : testCases) {
BigDecimal bd = testCase[0];
BigDecimal neg1 = bd.negate(mc);
BigDecimal neg2 = negateThenRound(bd, mc);
BigDecimal expected = testCase[1];
if (! neg1.equals(expected) ) {
failures++;
System.err.println("(" + bd + ").negate(" + mc + ") => " +
neg1 + " != expected " + expected);
}
if (! neg1.equals(neg2) ) {
failures++;
System.err.println("(" + bd + ").negate(" + mc + ") => " +
neg1 + " != ntr " + neg2);
}
// Test abs consistency
BigDecimal abs = bd.abs(mc);
BigDecimal expectedAbs = absThenRound(bd,mc);
if (! abs.equals(expectedAbs) ) {
failures++;
System.err.println("(" + bd + ").abs(" + mc + ") => " +
abs + " != atr " + expectedAbs);
}
}
return failures;
}
static int negateTests() {
int failures = 0;
BigDecimal [][] testCasesCeiling = {
{new BigDecimal("1.3"), new BigDecimal("-1")},
{new BigDecimal("-1.3"), new BigDecimal("2")},
};
failures += negateTest(testCasesCeiling,
new MathContext(1, RoundingMode.CEILING));
BigDecimal [][] testCasesFloor = {
{new BigDecimal("1.3"), new BigDecimal("-2")},
{new BigDecimal("-1.3"), new BigDecimal("1")},
};
failures += negateTest(testCasesFloor,
new MathContext(1, RoundingMode.FLOOR));
return failures;
}
public static void main(String argv[]) {
int failures = 0;
failures += negateTests();
if (failures > 0 )
throw new RuntimeException("Incurred " + failures + " failures" +
" testing the negate and/or abs.");
}
}

View file

@ -0,0 +1,95 @@
/*
* Copyright (c) 2003, 2025, 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.
*
* 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.
*/
/*
* @test
* @bug 4916097
* @summary Some exponent over/undeflow tests for the pow method
*/
import java.math.*;
public class PowTests {
static int zeroAndOneTests() {
int failures = 0;
BigDecimal[][] testCases = {
{BigDecimal.valueOf(0, Integer.MAX_VALUE), new BigDecimal(0), BigDecimal.valueOf(1, 0)},
{BigDecimal.valueOf(0, Integer.MAX_VALUE), new BigDecimal(1), BigDecimal.valueOf(0, Integer.MAX_VALUE)},
{BigDecimal.valueOf(0, Integer.MAX_VALUE), new BigDecimal(2), BigDecimal.valueOf(0, Integer.MAX_VALUE)},
{BigDecimal.valueOf(0, Integer.MAX_VALUE), new BigDecimal(999999999), BigDecimal.valueOf(0, Integer.MAX_VALUE)},
{BigDecimal.valueOf(0, Integer.MIN_VALUE), new BigDecimal(0), BigDecimal.valueOf(1, 0)},
{BigDecimal.valueOf(0, Integer.MIN_VALUE), new BigDecimal(1), BigDecimal.valueOf(0, Integer.MIN_VALUE)},
{BigDecimal.valueOf(0, Integer.MIN_VALUE), new BigDecimal(2), BigDecimal.valueOf(0, Integer.MIN_VALUE)},
{BigDecimal.valueOf(0, Integer.MIN_VALUE), new BigDecimal(999999999), BigDecimal.valueOf(0, Integer.MIN_VALUE)},
{BigDecimal.valueOf(1, Integer.MAX_VALUE), new BigDecimal(0), BigDecimal.valueOf(1, 0)},
{BigDecimal.valueOf(1, Integer.MAX_VALUE), new BigDecimal(1), BigDecimal.valueOf(1, Integer.MAX_VALUE)},
{BigDecimal.valueOf(1, Integer.MAX_VALUE), new BigDecimal(2), null}, // overflow
{BigDecimal.valueOf(1, Integer.MAX_VALUE), new BigDecimal(999999999), null}, // overflow
{BigDecimal.valueOf(1, Integer.MIN_VALUE), new BigDecimal(0), BigDecimal.valueOf(1, 0)},
{BigDecimal.valueOf(1, Integer.MIN_VALUE), new BigDecimal(1), BigDecimal.valueOf(1, Integer.MIN_VALUE)},
{BigDecimal.valueOf(1, Integer.MIN_VALUE), new BigDecimal(2), null}, // underflow
{BigDecimal.valueOf(1, Integer.MIN_VALUE), new BigDecimal(999999999), null}, // underflow
};
for(BigDecimal[] testCase: testCases) {
int exponent = testCase[1].intValueExact();
BigDecimal result;
try{
result = testCase[0].pow(exponent);
if (!result.equals(testCase[2]) ) {
failures++;
System.err.println("Unexpected result while raising " +
testCase[0] +
" to the " + exponent + " power; expected " +
testCase[2] + ", got " + result + ".");
}
} catch (ArithmeticException e) {
if (testCase[2] != null) {
failures++;
System.err.println("Unexpected exception while raising " + testCase[0] +
" to the " + exponent + " power.");
}
}
}
return failures;
}
public static void main(String argv[]) {
int failures = 0;
failures += zeroAndOneTests();
if (failures > 0) {
throw new RuntimeException("Incurred " + failures +
" failures while testing pow methods.");
}
}
}

View file

@ -0,0 +1,93 @@
/*
* Copyright (c) 2009, 2025, 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.
*
* 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.
*/
/*
* @test
* @bug 1234567
* @summary Test that precision() is computed properly.
*/
import java.math.*;
import static java.math.BigDecimal.*;
public class PrecisionTests {
private static BigDecimal NINE = valueOf(9);
public static void main(String argv[]) {
int failures = 0;
// Smallest and largest values of a given length
BigDecimal[] testValues = {
valueOf(1), valueOf(9),
};
failures += testPrecision(new BigDecimal(0), 1);
for(int i = 1; i < 100; i++) {
for(BigDecimal bd : testValues) {
failures += testPrecision(bd, i);
failures += testPrecision(bd.negate(), i);
}
testValues[0] = testValues[0].multiply(TEN);
testValues[1] = testValues[1].multiply(TEN).add(NINE);
}
// The following test tries to cover testings for precision of long values
BigDecimal[] randomTestValues = {
valueOf(2147483648L), // 2^31: 10 digits
valueOf(-2147483648L), // -2^31: 10 digits
valueOf(98893745455L), // random: 11 digits
valueOf(3455436789887L), // random: 13 digits
valueOf(140737488355328L), // 2^47: 15 digits
valueOf(-140737488355328L), // -2^47: 15 digits
valueOf(7564232235739573L), // random: 16 digits
valueOf(25335434990002322L), // random: 17 digits
valueOf(9223372036854775807L), // 2^63 - 1: 19 digits
valueOf(-9223372036854775807L) // -2^63 + 1: 19 digits
};
// The array below contains the expected precision of the above numbers
int[] expectedPrecision = {10, 10, 11, 13, 15, 15, 16, 17, 19, 19};
for (int i = 0; i < randomTestValues.length; i++) {
failures += testPrecision(randomTestValues[i], expectedPrecision[i]);
}
if (failures > 0) {
throw new RuntimeException("Incurred " + failures +
" failures while testing precision.");
}
}
private static int testPrecision(BigDecimal bd, int expected) {
int precision = bd.precision();
// System.out.printf("Testing %s, expected %d%n", bd, expected);
if (precision != expected) {
System.err.printf("For (%s).precision expected %d, got %d%n",
bd, expected, precision);
return 1;
}
return 0;
}
}

View file

@ -0,0 +1,245 @@
/*
* Copyright (c) 2003, 2018, 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.
*
* 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.
*/
/*
* @test
* @bug 7036582
* @summary Some new tests for the add method and constructor with MathContext.
* @run main RangeTests
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox -XX:AutoBoxCacheMax=20000 RangeTests
* @author Sergey V. Kuksenko
*/
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
public class RangeTests {
private static int addTest(BigDecimal arg1, BigDecimal arg2, BigDecimal expectedResult) {
int failures = 0;
BigDecimal result = arg1.add(arg2);
if (!result.equals(expectedResult)) {
System.out.println("Sum:" +
arg1 + " + " +
arg2 + " == " +
result + "; expected " +
expectedResult
);
failures++;
}
result = arg2.add(arg1);
if (!result.equals(expectedResult)) {
System.out.println("Sum:" +
arg2 + " + " +
arg1 + " == " +
result + "; expected " +
expectedResult
);
failures++;
}
return failures;
}
/*
* Test BigDecimal.add(BigDecimal) when values are withing different ranges:
* 1. within 32 bits
* 2. within 64 bits
* 3. outside 64 bits.
*/
private static int addBoundaryTest() {
int failures = 0;
failures += addTest(
new BigDecimal("85070591730234615847396907784232501249"),
BigDecimal.valueOf(0),
new BigDecimal("85070591730234615847396907784232501249") );
failures += addTest(
new BigDecimal("-85070591730234615847396907784232501249"),
BigDecimal.valueOf(0),
new BigDecimal("-85070591730234615847396907784232501249") );
failures += addTest(
new BigDecimal("85070591730234615847396907784232501249"),
BigDecimal.valueOf(1),
new BigDecimal("85070591730234615847396907784232501250") );
failures += addTest(
new BigDecimal("85070591730234615847396907784232501249"),
BigDecimal.valueOf(-1),
new BigDecimal("85070591730234615847396907784232501248") );
failures += addTest(
new BigDecimal("-85070591730234615847396907784232501250"),
BigDecimal.valueOf(-1),
new BigDecimal("-85070591730234615847396907784232501251") );
failures += addTest(
new BigDecimal("-85070591730234615847396907784232501249"),
BigDecimal.valueOf(1),
new BigDecimal("-85070591730234615847396907784232501248") );
failures += addTest(
new BigDecimal("147573952589676412927"),
BigDecimal.valueOf(Integer.MAX_VALUE),
new BigDecimal("147573952591823896574") );
failures += addTest(
new BigDecimal("-147573952589676412927"),
BigDecimal.valueOf(Integer.MAX_VALUE),
new BigDecimal("-147573952587528929280") );
failures += addTest(
new BigDecimal("79228162514264337593543950335"),
BigDecimal.valueOf(999),
new BigDecimal("79228162514264337593543951334") );
failures += addTest(
new BigDecimal("79228162514264337593543950335"),
BigDecimal.valueOf(Integer.MAX_VALUE/2),
new BigDecimal("79228162514264337594617692158") );
failures += addTest(
new BigDecimal("79228162514264337593543950335"),
BigDecimal.valueOf(Integer.MIN_VALUE/2),
new BigDecimal("79228162514264337592470208511") );
failures += addTest(
new BigDecimal("-79228162514264337593543950335"),
BigDecimal.valueOf(Integer.MAX_VALUE/2),
new BigDecimal("-79228162514264337592470208512") );
failures += addTest(
new BigDecimal("79228162514264337593543950335"),
BigDecimal.valueOf(-(Integer.MIN_VALUE/2)),
new BigDecimal("79228162514264337594617692159") );
failures += addTest(
new BigDecimal("79228162514264337593543950335"),
BigDecimal.valueOf(Long.MAX_VALUE/2),
new BigDecimal("79228162518876023611971338238") );
failures += addTest(
new BigDecimal("79228162514264337593543950335"),
BigDecimal.valueOf(Long.MIN_VALUE/2),
new BigDecimal("79228162509652651575116562431") );
failures += addTest(
new BigDecimal("-79228162514264337593543950335"),
BigDecimal.valueOf(Long.MAX_VALUE/2),
new BigDecimal("-79228162509652651575116562432") );
failures += addTest(
new BigDecimal("79228162514264337593543950335"),
BigDecimal.valueOf(-(Long.MIN_VALUE/2)),
new BigDecimal("79228162518876023611971338239") );
failures += addTest(
new BigDecimal("-9223372036854775808"),
BigDecimal.valueOf(1),
new BigDecimal("-9223372036854775807") );
failures += addTest(
new BigDecimal("-9223372036854775808"),
BigDecimal.valueOf(Long.MAX_VALUE/2),
new BigDecimal("-4611686018427387905") );
failures += addTest(
new BigDecimal("9223372036854775808"),
BigDecimal.valueOf(-1),
new BigDecimal("9223372036854775807") );
failures += addTest(
new BigDecimal("9223372036854775808"),
BigDecimal.valueOf(-Long.MAX_VALUE/2),
new BigDecimal("4611686018427387905") );
return failures;
}
private static int testRoundingFromBigInteger(BigInteger bi, int scale, MathContext mc) {
int failures = 0;
BigDecimal bd1 = new BigDecimal(bi,scale, mc);
BigDecimal bd2 = (new BigDecimal(bi,scale)).round(mc);
if (!bd1.equals(bd2)) {
System.out.println("new BigDecimal(BigInteger,int,MathContext):" +
"BigInteger == " +
bi + "; scale == " + scale + "; result == " +
bd1 + "; expected == " +
bd2
);
failures++;
}
return failures;
}
private static int roundingConstructorTest() {
int failures = 0;
failures += testRoundingFromBigInteger(
new BigInteger("85070591730234615847396907784232501249"),
7, MathContext.DECIMAL64);
failures += testRoundingFromBigInteger(
new BigInteger("85070591730234615847396907784232501249"),
0, MathContext.DECIMAL64);
failures += testRoundingFromBigInteger(
new BigInteger("85070591730234615847396907784232501249"),
-7, MathContext.DECIMAL64);
failures += testRoundingFromBigInteger(
new BigInteger("85070591730234615847396907784232501249"),
7, MathContext.DECIMAL128);
failures += testRoundingFromBigInteger(
new BigInteger("85070591730234615847396907784232501249"),
177, MathContext.DECIMAL128);
failures += testRoundingFromBigInteger(
new BigInteger("85070591730234615847396907784232501249"),
177, MathContext.DECIMAL32);
failures += testRoundingFromBigInteger(
new BigInteger("85070591730234615847396907784232501249"),
177, MathContext.UNLIMITED);
failures += testRoundingFromBigInteger(
new BigInteger("85070591730234615847396907784232501249"),
0, MathContext.UNLIMITED);
return failures;
}
private static int minLongConstructorTest(MathContext mc) {
int failures = 0;
BigDecimal bd1 = new BigDecimal(Long.MIN_VALUE,mc);
BigDecimal bd2 = new BigDecimal(Long.MIN_VALUE).round(mc);
if (!bd1.equals(bd2)) {
System.out.println("new BigDecimal(long,MathContext):" +
"long == " +
Long.MIN_VALUE + "; result == " +
bd1 + "; expected == " +
bd2
);
failures++;
}
return failures;
}
private static int minLongConstructorTest() {
int failures = 0;
failures+=minLongConstructorTest(MathContext.UNLIMITED);
failures+=minLongConstructorTest(MathContext.DECIMAL32);
failures+=minLongConstructorTest(MathContext.DECIMAL64);
failures+=minLongConstructorTest(MathContext.DECIMAL128);
return failures;
}
public static void main(String argv[]) {
int failures = 0;
failures += addBoundaryTest();
failures += roundingConstructorTest();
failures += minLongConstructorTest();
if (failures > 0) {
throw new RuntimeException("Incurred " + failures +
" failures while testing.");
}
}
}

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2005, 2025, 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.
*
* 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.
*/
/*
* @test
* @bug 6334849
* @summary Tests of dropping digits near the scale threshold
*/
import java.math.*;
public class RoundingTests {
private static int roundingTests() {
int failures = 0;
BigDecimal bd1 = BigDecimal.valueOf(11, Integer.MIN_VALUE);
BigDecimal bd2 = null;
MathContext mc = new MathContext(1);
try {
bd2 = bd1.round(mc); // should overflow here
failures++;
System.err.printf("Did not get expected overflow rounding %s to %d digits, got %s%n",
bd1, mc.getPrecision(), bd2);
} catch(ArithmeticException e) {
; // expected
}
return failures;
}
public static void main(String argv[]) {
int failures = 0;
failures += roundingTests();
if (failures > 0) {
System.err.println("Encountered " + failures +
" failures while testing rounding.");
throw new RuntimeException();
}
}
}

View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2003, 2025, 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.
*
* 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.
*/
/*
* @test
* @bug 4899722
* @summary Basic tests of scaleByPowerOfTen
*/
import java.math.*;
public class ScaleByPowerOfTenTests {
public static void main(String argv[]) {
for (int i = -10; i < 10; i++) {
BigDecimal bd = BigDecimal.ONE.scaleByPowerOfTen(i);
BigDecimal expected;
if (!bd.equals(expected = new BigDecimal(BigInteger.ONE, -i))) {
throw new RuntimeException("Unexpected result " +
bd.toString() +
"; expected " +
expected.toString());
}
bd = BigDecimal.ONE.negate().scaleByPowerOfTen(i);
if (!bd.equals(expected = new BigDecimal(BigInteger.ONE.negate(), -i))) {
throw new RuntimeException("Unexpected result " +
bd.toString() +
"; expected " +
expected.toString());
}
}
}
}

View file

@ -0,0 +1,150 @@
/*
* Copyright (c) 2005, 2022, 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.
*
* 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.
*/
/*
* @test
* @bug 6177836 8282252
* @summary Verify BigDecimal objects with collapsed values are serialized properly.
*/
import java.math.*;
import java.io.*;
import java.util.List;
public class SerializationTests {
public static void main(String... args) throws Exception {
checkBigDecimalSerialRoundTrip();
checkBigDecimalSubSerialRoundTrip();
}
private static void checkSerialForm(BigDecimal bd) throws Exception {
checkSerialForm0(bd);
checkSerialForm0(bd.negate());
}
private static void checkSerialForm0(BigDecimal bd) throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try(ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(bd);
oos.flush();
}
ObjectInputStream ois = new
ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
BigDecimal tmp = (BigDecimal)ois.readObject();
if (!bd.equals(tmp) ||
bd.hashCode() != tmp.hashCode() ||
bd.getClass() != tmp.getClass() ||
// Directly test equality of components
bd.scale() != tmp.scale() ||
!bd.unscaledValue().equals(tmp.unscaledValue())) {
System.err.print(" original : " + bd);
System.err.println(" (hash: 0x" + Integer.toHexString(bd.hashCode()) + ")");
System.err.print("serialized : " + tmp);
System.err.println(" (hash: 0x" + Integer.toHexString(tmp.hashCode()) + ")");
throw new RuntimeException("Bad serial roundtrip");
}
// If the class of the deserialized number is BigDecimal,
// verify the implementation constraint on the unscaled value
// having BigInteger class
if (tmp.getClass() == BigDecimal.class) {
if (tmp.unscaledValue().getClass() != BigInteger.class) {
throw new RuntimeException("Not using genuine BigInteger as an unscaled value");
}
}
}
private static class BigIntegerSub extends BigInteger {
public BigIntegerSub(BigInteger bi) {
super(bi.toByteArray());
}
@Override
public String toString() {
return java.util.Arrays.toString(toByteArray());
}
}
private static void checkBigDecimalSerialRoundTrip() throws Exception {
var values =
List.of(BigDecimal.ZERO,
BigDecimal.ONE,
BigDecimal.TEN,
new BigDecimal(0),
new BigDecimal(1),
new BigDecimal(10),
new BigDecimal(Integer.MAX_VALUE),
new BigDecimal(Long.MAX_VALUE-1),
new BigDecimal(BigInteger.valueOf(1), 1),
new BigDecimal(BigInteger.valueOf(100), 50),
new BigDecimal(new BigInteger("9223372036854775808"), // Long.MAX_VALUE + 1
Integer.MAX_VALUE),
new BigDecimal(new BigInteger("9223372036854775808"), // Long.MAX_VALUE + 1
Integer.MIN_VALUE),
new BigDecimal(new BigIntegerSub(BigInteger.ONE), 2));
for(BigDecimal value : values) {
checkSerialForm(value);
}
}
private static class BigDecimalSub extends BigDecimal {
public BigDecimalSub(BigDecimal bd) {
super(bd.unscaledValue(), bd.scale());
}
@Override
public String toString() {
return unscaledValue() + "x10^" + (-scale());
}
}
// Subclass defining a serialVersionUID
private static class BigDecimalSubSVUID extends BigDecimal {
@java.io.Serial
private static long serialVesionUID = 0x0123_4567_89ab_cdefL;
public BigDecimalSubSVUID(BigDecimal bd) {
super(bd.unscaledValue(), bd.scale());
}
}
private static void checkBigDecimalSubSerialRoundTrip() throws Exception {
var values =
List.of(BigDecimal.ZERO,
BigDecimal.ONE,
BigDecimal.TEN,
new BigDecimal(BigInteger.TEN, 1234),
new BigDecimal(new BigInteger("9223372036854775808"), // Long.MAX_VALUE + 1
Integer.MAX_VALUE),
new BigDecimal(new BigInteger("9223372036854775808"), // Long.MAX_VALUE + 1
Integer.MIN_VALUE));
for(var value : values) {
checkSerialForm(new BigDecimalSub(value));
checkSerialForm(new BigDecimalSubSVUID(value));
}
}
}

View file

@ -0,0 +1,834 @@
/*
* Copyright (c) 2016, 2025, 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.
*
* 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.
*/
/*
* @test
* @bug 4851777 8233452 8341402
* @summary Tests of BigDecimal.sqrt().
*/
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.List;
import static java.math.BigDecimal.ONE;
import static java.math.BigDecimal.TWO;
import static java.math.BigDecimal.TEN;
import static java.math.BigDecimal.ZERO;
import static java.math.BigDecimal.valueOf;
public class SquareRootTests {
/**
* The value 0.1, with a scale of 1.
*/
private static final BigDecimal ONE_TENTH = valueOf(1L, 1);
public static void main(String... args) {
int failures = 0;
failures += negativeTests();
failures += zeroTests();
failures += oneDigitTests();
failures += twoDigitTests();
failures += evenPowersOfTenTests();
failures += squareRootTwoTests();
failures += lowPrecisionPerfectSquares();
failures += almostFourRoundingDown();
failures += almostFourRoundingUp();
failures += nearTen();
failures += nearOne();
failures += halfWay();
failures += exactResultTests();
failures += scaleOverflowTest();
if (failures > 0 ) {
throw new RuntimeException("Incurred " + failures + " failures" +
" testing BigDecimal.sqrt().");
}
}
private static int negativeTests() {
int failures = 0;
for (long i = -10; i < 0; i++) {
for (int j = -5; j < 5; j++) {
try {
BigDecimal input = BigDecimal.valueOf(i, j);
BigDecimal result = input.sqrt(MathContext.DECIMAL64);
System.err.println("Unexpected sqrt of negative: (" +
input + ").sqrt() = " + result );
failures += 1;
} catch (ArithmeticException e) {
; // Expected
}
}
}
return failures;
}
private static int zeroTests() {
int failures = 0;
for (int i = -100; i < 100; i++) {
BigDecimal expected = BigDecimal.valueOf(0L, i/2);
// These results are independent of rounding mode
failures += compare(BigDecimal.valueOf(0L, i).sqrt(MathContext.UNLIMITED),
expected, true, "zeros");
failures += compare(BigDecimal.valueOf(0L, i).sqrt(MathContext.DECIMAL64),
expected, true, "zeros");
}
return failures;
}
/**
* Probe inputs with one digit of precision, 1 ... 9 and those
* values scaled by 10^-1, 0.1, ... 0.9.
*/
private static int oneDigitTests() {
int failures = 0;
List<BigDecimal> oneToNine =
List.of(ONE, TWO, valueOf(3),
valueOf(4), valueOf(5), valueOf(6),
valueOf(7), valueOf(8), valueOf(9));
List<RoundingMode> modes =
List.of(RoundingMode.UP, RoundingMode.DOWN,
RoundingMode.CEILING, RoundingMode.FLOOR,
RoundingMode.HALF_UP, RoundingMode.HALF_DOWN, RoundingMode.HALF_EVEN);
for (int i = 1; i < 20; i++) {
for (RoundingMode rm : modes) {
for (BigDecimal bd : oneToNine) {
MathContext mc = new MathContext(i, rm);
failures += compareSqrtImplementations(bd, mc);
bd = bd.multiply(ONE_TENTH);
failures += compareSqrtImplementations(bd, mc);
}
}
}
return failures;
}
/**
* Probe inputs with two digits of precision, (10 ... 99) and
* those values scaled by 10^-1 (1, ... 9.9) and scaled by 10^-2
* (0.1 ... 0.99).
*/
private static int twoDigitTests() {
int failures = 0;
List<RoundingMode> modes =
List.of(RoundingMode.UP, RoundingMode.DOWN,
RoundingMode.CEILING, RoundingMode.FLOOR,
RoundingMode.HALF_UP, RoundingMode.HALF_DOWN, RoundingMode.HALF_EVEN);
for (int i = 10; i < 100; i++) {
BigDecimal bd0 = BigDecimal.valueOf(i);
BigDecimal bd1 = bd0.multiply(ONE_TENTH);
BigDecimal bd2 = bd1.multiply(ONE_TENTH);
for (BigDecimal bd : List.of(bd0, bd1, bd2)) {
for (int precision = 1; i < 20; i++) {
for (RoundingMode rm : modes) {
MathContext mc = new MathContext(precision, rm);
failures += compareSqrtImplementations(bd, mc);
}
}
}
}
return failures;
}
private static int compareSqrtImplementations(BigDecimal bd, MathContext mc) {
return equalNumerically(BigSquareRoot.sqrt(bd, mc),
bd.sqrt(mc), "sqrt(" + bd + ") under " + mc);
}
private static int exactResultTests() {
int failures = 0;
MathContext unnecessary = new MathContext(1, RoundingMode.UNNECESSARY);
MathContext arbitrary = new MathContext(0, RoundingMode.CEILING);
BigDecimal[] errCases = {
// (strippedScale & 1) != 0
BigDecimal.TEN,
// (strippedScale & 1) == 0 && !stripped.isPowerOfTen() && sqrtRem[1].signum != 0
BigDecimal.TWO,
};
for (BigDecimal input : errCases) {
BigDecimal result;
// mc.roundingMode == RoundingMode.UNNECESSARY
try {
result = input.sqrt(unnecessary);
System.err.println("Unexpected sqrt with UNNECESSARY RoundingMode: (" + input + ").sqrt() = " + result);
failures += 1;
} catch (ArithmeticException e) {
// Expected
}
// mc.roundingMode != RoundingMode.UNNECESSARY && mc.precision == 0
try {
result = input.sqrt(arbitrary);
System.err.println("Unexpected sqrt with mc.precision == 0: (" + input + ").sqrt() = " + result);
failures += 1;
} catch (ArithmeticException e) {
// Expected
}
}
// (strippedScale & 1) == 0
// !stripped.isPowerOfTen() && sqrtRem[1].signum == 0 && (mc.precision != 0 && result.precision() > mc.precision)
try {
BigDecimal input = BigDecimal.valueOf(121);
BigDecimal result = input.sqrt(unnecessary);
System.err.println("Unexpected sqrt with result.precision() > mc.precision: ("
+ input + ").sqrt() = " + result);
failures += 1;
} catch (ArithmeticException e) {
// Expected
}
BigDecimal four = BigDecimal.valueOf(4);
Object[][] cases = {
// stripped.isPowerOfTen() && mc.roundingMode == RoundingMode.UNNECESSARY
{ BigDecimal.ONE, unnecessary, BigDecimal.ONE },
// stripped.isPowerOfTen() && mc.roundingMode != RoundingMode.UNNECESSARY && mc.precision == 0
{ BigDecimal.ONE, arbitrary, BigDecimal.ONE },
// !stripped.isPowerOfTen() && mc.roundingMode == RoundingMode.UNNECESSARY
// && sqrtRem[1].signum == 0 && mc.precision == 0
{ four, new MathContext(0, RoundingMode.UNNECESSARY), BigDecimal.TWO },
// !stripped.isPowerOfTen() && mc.roundingMode != RoundingMode.UNNECESSARY
// && sqrtRem[1].signum == 0 && mc.precision == 0
{ four, arbitrary, BigDecimal.TWO },
// !stripped.isPowerOfTen() && sqrtRem[1].signum == 0
// && (mc.precision != 0 && result.precision() <= mc.precision)
{ four, unnecessary, BigDecimal.TWO },
};
for (Object[] testCase : cases) {
BigDecimal expected = (BigDecimal) testCase[2];
BigDecimal result = ((BigDecimal) testCase[0]).sqrt((MathContext) testCase[1]);
failures += compare(expected, result, true, "Exact results");
}
return failures;
}
private static int scaleOverflowTest() {
int failures = 0;
try {
BigDecimal.valueOf(1, -1).sqrt(new MathContext((1 << 30) + 1, RoundingMode.UP));
System.err.println("ArithmeticException expected: possible overflow undetected "
+ "or the range of supported values for the algorithm has extended.");
failures += 1;
} catch (ArithmeticException e) {
// Expected
}
return failures;
}
/**
* sqrt(10^2N) is 10^N
* Both numerical value and representation should be verified
*/
private static int evenPowersOfTenTests() {
int failures = 0;
MathContext oneDigitExactly = new MathContext(1, RoundingMode.UNNECESSARY);
for (int scale = -100; scale <= 100; scale++) {
BigDecimal testValue = BigDecimal.valueOf(1, 2*scale);
BigDecimal expectedNumericalResult = BigDecimal.valueOf(1, scale);
BigDecimal result;
failures += equalNumerically(expectedNumericalResult,
result = testValue.sqrt(MathContext.DECIMAL64),
"Even powers of 10, DECIMAL64");
// Can round to one digit of precision exactly
failures += equalNumerically(expectedNumericalResult,
result = testValue.sqrt(oneDigitExactly),
"even powers of 10, 1 digit");
if (result.precision() > 1) {
failures += 1;
System.err.println("Excess precision for " + result);
}
// If rounding to more than one digit, do precision / scale checking...
}
return failures;
}
private static int squareRootTwoTests() {
int failures = 0;
// Square root of 2 truncated to 65 digits
BigDecimal highPrecisionRoot2 =
new BigDecimal("1.41421356237309504880168872420969807856967187537694807317667973799");
RoundingMode[] modes = {
RoundingMode.UP, RoundingMode.DOWN,
RoundingMode.CEILING, RoundingMode.FLOOR,
RoundingMode.HALF_UP, RoundingMode.HALF_DOWN, RoundingMode.HALF_EVEN
};
// For each interesting rounding mode, for precisions 1 to, say,
// 63 numerically compare TWO.sqrt(mc) to
// highPrecisionRoot2.round(mc) and the alternative internal high-precision
// implementation of square root.
for (RoundingMode mode : modes) {
for (int precision = 1; precision < 63; precision++) {
MathContext mc = new MathContext(precision, mode);
BigDecimal expected = highPrecisionRoot2.round(mc);
BigDecimal computed = TWO.sqrt(mc);
BigDecimal altComputed = BigSquareRoot.sqrt(TWO, mc);
failures += equalNumerically(expected, computed, "sqrt(2)");
failures += equalNumerically(computed, altComputed, "computed & altComputed");
}
}
return failures;
}
private static int lowPrecisionPerfectSquares() {
int failures = 0;
// For 5^2 through 9^2, if the input is rounded to one digit
// first before the root is computed, the wrong answer will
// result. Verify results and scale for different rounding
// modes and precisions.
long[][] squaresWithOneDigitRoot = {{ 4, 2},
{ 9, 3},
{25, 5},
{36, 6},
{49, 7},
{64, 8},
{81, 9}};
for (long[] squareAndRoot : squaresWithOneDigitRoot) {
BigDecimal square = new BigDecimal(squareAndRoot[0]);
BigDecimal expected = new BigDecimal(squareAndRoot[1]);
for (int scale = 0; scale <= 4; scale++) {
BigDecimal scaledSquare = square.setScale(scale, RoundingMode.UNNECESSARY);
int expectedScale = Math.ceilDiv(scale, 2);
for (int precision = 0; precision <= 5; precision++) {
for (RoundingMode rm : RoundingMode.values()) {
MathContext mc = new MathContext(precision, rm);
BigDecimal computedRoot = scaledSquare.sqrt(mc);
failures += equalNumerically(expected, computedRoot, "simple squares");
int computedScale = computedRoot.scale();
if (precision >= expectedScale + 1 &&
computedScale != expectedScale) {
System.err.printf("%s\tprecision=%d\trm=%s%n",
computedRoot.toString(), precision, rm);
failures++;
System.err.printf("\t%s does not have expected scale of %d%n.",
computedRoot, expectedScale);
}
}
}
}
}
return failures;
}
/**
* Test around 3.9999 that the sqrt doesn't improperly round-up to
* a numerical value of 2.
*/
private static int almostFourRoundingDown() {
int failures = 0;
BigDecimal nearFour = new BigDecimal("3.999999999999999999999999999999");
// Sqrt is 1.9999...
for (int i = 1; i < 64; i++) {
MathContext mc = new MathContext(i, RoundingMode.FLOOR);
BigDecimal result = nearFour.sqrt(mc);
BigDecimal expected = BigSquareRoot.sqrt(nearFour, mc);
failures += equalNumerically(expected, result, "near four rounding down");
failures += (result.compareTo(TWO) < 0) ? 0 : 1 ;
}
return failures;
}
/**
* Test around 4.000...1 that the sqrt doesn't improperly
* round-down to a numerical value of 2.
*/
private static int almostFourRoundingUp() {
int failures = 0;
BigDecimal nearFour = new BigDecimal("4.000000000000000000000000000001");
// Sqrt is 2.0000....<non-zero digits>
for (int i = 1; i < 64; i++) {
MathContext mc = new MathContext(i, RoundingMode.CEILING);
BigDecimal result = nearFour.sqrt(mc);
BigDecimal expected = BigSquareRoot.sqrt(nearFour, mc);
failures += equalNumerically(expected, result, "near four rounding up");
failures += (result.compareTo(TWO) > 0) ? 0 : 1 ;
}
return failures;
}
private static int nearTen() {
int failures = 0;
BigDecimal near10 = new BigDecimal("9.99999999999999999999");
BigDecimal near10sq = near10.multiply(near10);
BigDecimal near10sq_ulp = near10sq.add(near10sq.ulp());
for (int i = 10; i < 23; i++) {
MathContext mc = new MathContext(i, RoundingMode.HALF_EVEN);
failures += equalNumerically(BigSquareRoot.sqrt(near10sq_ulp, mc),
near10sq_ulp.sqrt(mc),
"near 10 rounding half even");
}
return failures;
}
/*
* Probe for rounding failures near a power of ten, 1 = 10^0,
* where an ulp has a different size above and below the value.
*/
private static int nearOne() {
int failures = 0;
BigDecimal near1 = new BigDecimal(".999999999999999999999");
BigDecimal near1sq = near1.multiply(near1);
BigDecimal near1sq_ulp = near1sq.add(near1sq.ulp());
for (int i = 10; i < 23; i++) {
for (RoundingMode rm : List.of(RoundingMode.HALF_EVEN,
RoundingMode.UP,
RoundingMode.DOWN )) {
MathContext mc = new MathContext(i, rm);
failures += equalNumerically(BigSquareRoot.sqrt(near1sq_ulp, mc),
near1sq_ulp.sqrt(mc),
mc.toString());
}
}
return failures;
}
private static int halfWay() {
int failures = 0;
/*
* Use enough digits that the exact result cannot be computed
* from the sqrt of a double.
*/
BigDecimal[] halfWayCases = {
// Odd next digit, truncate on HALF_EVEN
new BigDecimal("123456789123456789.5"),
// Even next digit, round up on HALF_EVEN
new BigDecimal("123456789123456788.5"),
};
for (BigDecimal halfWayCase : halfWayCases) {
// Round result to next-to-last place
int precision = halfWayCase.precision() - 1;
BigDecimal square = halfWayCase.multiply(halfWayCase);
for (RoundingMode rm : List.of(RoundingMode.HALF_EVEN,
RoundingMode.HALF_UP,
RoundingMode.HALF_DOWN)) {
MathContext mc = new MathContext(precision, rm);
System.out.println("\nRounding mode " + rm);
System.out.println("\t" + halfWayCase.round(mc) + "\t" + halfWayCase);
System.out.println("\t" + BigSquareRoot.sqrt(square, mc));
failures += equalNumerically(/*square.sqrt(mc),*/
BigSquareRoot.sqrt(square, mc),
halfWayCase.round(mc),
"Rounding halway " + rm);
}
}
return failures;
}
private static int compare(BigDecimal a, BigDecimal b, boolean expected, String prefix) {
boolean result = a.equals(b);
int failed = (result==expected) ? 0 : 1;
if (failed == 1) {
System.err.println("Testing " + prefix +
"(" + a + ").compareTo(" + b + ") => " + result +
"\n\tExpected " + expected);
}
return failed;
}
private static int equalNumerically(BigDecimal a, BigDecimal b,
String prefix) {
return compareNumerically(a, b, 0, prefix);
}
private static int compareNumerically(BigDecimal a, BigDecimal b,
int expected, String prefix) {
int result = a.compareTo(b);
int failed = (result==expected) ? 0 : 1;
if (failed == 1) {
System.err.println("Testing " + prefix +
"(" + a + ").compareTo(" + b + ") => " + result +
"\n\tExpected " + expected);
}
return failed;
}
/**
* Alternative implementation of BigDecimal square root which uses
* higher-precision for a simpler set of termination conditions
* for the Newton iteration.
*/
private static class BigSquareRoot {
/**
* The value 0.5, with a scale of 1.
*/
private static final BigDecimal ONE_HALF = valueOf(5L, 1);
public static boolean isPowerOfTen(BigDecimal bd) {
return BigInteger.ONE.equals(bd.unscaledValue());
}
public static BigDecimal square(BigDecimal bd) {
return bd.multiply(bd);
}
public static BigDecimal sqrt(BigDecimal bd, MathContext mc) {
int signum = bd.signum();
if (signum == 1) {
/*
* The following code draws on the algorithm presented in
* "Properly Rounded Variable Precision Square Root," Hull and
* Abrham, ACM Transactions on Mathematical Software, Vol 11,
* No. 3, September 1985, Pages 229-237.
*
* The BigDecimal computational model differs from the one
* presented in the paper in several ways: first BigDecimal
* numbers aren't necessarily normalized, second many more
* rounding modes are supported, including UNNECESSARY, and
* exact results can be requested.
*
* The main steps of the algorithm below are as follows,
* first argument reduce the value to the numerical range
* [1, 10) using the following relations:
*
* x = y * 10 ^ exp
* sqrt(x) = sqrt(y) * 10^(exp / 2) if exp is even
* sqrt(x) = sqrt(y/10) * 10 ^((exp+1)/2) is exp is odd
*
* Then use Newton's iteration on the reduced value to compute
* the numerical digits of the desired result.
*
* Finally, scale back to the desired exponent range and
* perform any adjustment to get the preferred scale in the
* representation.
*/
// The code below favors relative simplicity over checking
// for special cases that could run faster.
int preferredScale = Math.ceilDiv(bd.scale(), 2);
BigDecimal zeroWithFinalPreferredScale =
BigDecimal.valueOf(0L, preferredScale);
// First phase of numerical normalization, strip trailing
// zeros and check for even powers of 10.
BigDecimal stripped = bd.stripTrailingZeros();
int strippedScale = stripped.scale();
// Numerically sqrt(10^2N) = 10^N
if (isPowerOfTen(stripped) &&
strippedScale % 2 == 0) {
BigDecimal result = BigDecimal.valueOf(1L, strippedScale/2);
if (result.scale() != preferredScale) {
// Adjust to requested precision and preferred
// scale as appropriate.
result = result.add(zeroWithFinalPreferredScale, mc);
}
return result;
}
// After stripTrailingZeros, the representation is normalized as
//
// unscaledValue * 10^(-scale)
//
// where unscaledValue is an integer with the mimimum
// precision for the cohort of the numerical value. To
// allow binary floating-point hardware to be used to get
// approximately a 15 digit approximation to the square
// root, it is helpful to instead normalize this so that
// the significand portion is to right of the decimal
// point by roughly (scale() - precision() + 1).
// Now the precision / scale adjustment
int scaleAdjust = 0;
int scale = stripped.scale() - stripped.precision() + 1;
if (scale % 2 == 0) {
scaleAdjust = scale;
} else {
scaleAdjust = scale - 1;
}
BigDecimal working = stripped.scaleByPowerOfTen(scaleAdjust);
assert // Verify 0.1 <= working < 10
ONE_TENTH.compareTo(working) <= 0 && working.compareTo(TEN) < 0;
// Use good ole' Math.sqrt to get the initial guess for
// the Newton iteration, good to at least 15 decimal
// digits. This approach does incur the cost of a
//
// BigDecimal -> double -> BigDecimal
//
// conversion cycle, but it avoids the need for several
// Newton iterations in BigDecimal arithmetic to get the
// working answer to 15 digits of precision. If many fewer
// than 15 digits were needed, it might be faster to do
// the loop entirely in BigDecimal arithmetic.
//
// (A double value might have as much many as 17 decimal
// digits of precision; it depends on the relative density
// of binary and decimal numbers at different regions of
// the number line.)
//
// (It would be possible to check for certain special
// cases to avoid doing any Newton iterations. For
// example, if the BigDecimal -> double conversion was
// known to be exact and the rounding mode had a
// low-enough precision, the post-Newton rounding logic
// could be applied directly.)
BigDecimal guess = new BigDecimal(Math.sqrt(working.doubleValue()));
int guessPrecision = 15;
int originalPrecision = mc.getPrecision();
int targetPrecision;
// If an exact value is requested, it must only need
// about half of the input digits to represent since
// multiplying an N digit number by itself yield a (2N
// - 1) digit or 2N digit result.
if (originalPrecision == 0) {
targetPrecision = stripped.precision()/2 + 1;
} else {
targetPrecision = originalPrecision;
}
// When setting the precision to use inside the Newton
// iteration loop, take care to avoid the case where the
// precision of the input exceeds the requested precision
// and rounding the input value too soon.
BigDecimal approx = guess;
int workingPrecision = working.precision();
// Use "2p + 2" property to guarantee enough
// intermediate precision so that a double-rounding
// error does not occur when rounded to the final
// destination precision.
int loopPrecision =
Math.max(2 * Math.max(targetPrecision, workingPrecision) + 2,
34); // Force at least two Netwon
// iterations on the Math.sqrt
// result.
do {
MathContext mcTmp = new MathContext(loopPrecision, RoundingMode.HALF_EVEN);
// approx = 0.5 * (approx + fraction / approx)
approx = ONE_HALF.multiply(approx.add(working.divide(approx, mcTmp), mcTmp));
guessPrecision *= 2;
} while (guessPrecision < loopPrecision);
BigDecimal result;
RoundingMode targetRm = mc.getRoundingMode();
if (targetRm == RoundingMode.UNNECESSARY || originalPrecision == 0) {
RoundingMode tmpRm =
(targetRm == RoundingMode.UNNECESSARY) ? RoundingMode.DOWN : targetRm;
MathContext mcTmp = new MathContext(targetPrecision, tmpRm);
result = approx.scaleByPowerOfTen(-scaleAdjust/2).round(mcTmp);
// If result*result != this numerically, the square
// root isn't exact
if (bd.subtract(square(result)).compareTo(ZERO) != 0) {
throw new ArithmeticException("Computed square root not exact.");
}
} else {
result = approx.scaleByPowerOfTen(-scaleAdjust/2).round(mc);
}
assert squareRootResultAssertions(bd, result, mc);
if (result.scale() != preferredScale) {
// The preferred scale of an add is
// max(addend.scale(), augend.scale()). Therefore, if
// the scale of the result is first minimized using
// stripTrailingZeros(), adding a zero of the
// preferred scale rounding the correct precision will
// perform the proper scale vs precision tradeoffs.
result = result.stripTrailingZeros().
add(zeroWithFinalPreferredScale,
new MathContext(originalPrecision, RoundingMode.UNNECESSARY));
}
return result;
} else {
switch (signum) {
case -1:
throw new ArithmeticException("Attempted square root " +
"of negative BigDecimal");
case 0:
return valueOf(0L, bd.scale()/2);
default:
throw new AssertionError("Bad value from signum");
}
}
}
/**
* For nonzero values, check numerical correctness properties of
* the computed result for the chosen rounding mode.
*
* For the directed roundings, for DOWN and FLOOR, result^2 must
* be {@code <=} the input and (result+ulp)^2 must be {@code >} the
* input. Conversely, for UP and CEIL, result^2 must be {@code >=} the
* input and (result-ulp)^2 must be {@code <} the input.
*/
private static boolean squareRootResultAssertions(BigDecimal input, BigDecimal result, MathContext mc) {
if (result.signum() == 0) {
return squareRootZeroResultAssertions(input, result, mc);
} else {
RoundingMode rm = mc.getRoundingMode();
BigDecimal ulp = result.ulp();
BigDecimal neighborUp = result.add(ulp);
// Make neighbor down accurate even for powers of ten
if (isPowerOfTen(result)) {
ulp = ulp.divide(TEN);
}
BigDecimal neighborDown = result.subtract(ulp);
// Both the starting value and result should be nonzero and positive.
if (result.signum() != 1 ||
input.signum() != 1) {
return false;
}
switch (rm) {
case DOWN:
case FLOOR:
assert
square(result).compareTo(input) <= 0 &&
square(neighborUp).compareTo(input) > 0:
"Square of result out for bounds rounding " + rm;
return true;
case UP:
case CEILING:
assert
square(result).compareTo(input) >= 0 :
"Square of result too small rounding " + rm;
assert
square(neighborDown).compareTo(input) < 0 :
"Square of down neighbor too large rounding " + rm + "\n" +
"\t input: " + input + "\t neighborDown: " + neighborDown +"\t sqrt: " + result +
"\t" + mc;
return true;
case HALF_DOWN:
case HALF_EVEN:
case HALF_UP:
BigDecimal err = square(result).subtract(input).abs();
BigDecimal errUp = square(neighborUp).subtract(input);
BigDecimal errDown = input.subtract(square(neighborDown));
// All error values should be positive so don't need to
// compare absolute values.
int err_comp_errUp = err.compareTo(errUp);
int err_comp_errDown = err.compareTo(errDown);
assert
errUp.signum() == 1 &&
errDown.signum() == 1 :
"Errors of neighbors squared don't have correct signs";
// At least one of these must be true, but not both
// assert
// err_comp_errUp <= 0 : "Upper neighbor is closer than result: " + rm +
// "\t" + input + "\t result" + result;
// assert
// err_comp_errDown <= 0 : "Lower neighbor is closer than result: " + rm +
// "\t" + input + "\t result " + result + "\t lower neighbor: " + neighborDown;
assert
((err_comp_errUp == 0 ) ? err_comp_errDown < 0 : true) &&
((err_comp_errDown == 0 ) ? err_comp_errUp < 0 : true) :
"Incorrect error relationships";
// && could check for digit conditions for ties too
return true;
default: // Definition of UNNECESSARY already verified.
return true;
}
}
}
private static boolean squareRootZeroResultAssertions(BigDecimal input,
BigDecimal result,
MathContext mc) {
return input.compareTo(ZERO) == 0;
}
}
}

View file

@ -0,0 +1,185 @@
/*
* Copyright (c) 1999, 2022, 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.
*
* 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.
*/
/*
* @test
* @library /test/lib
* @build jdk.test.lib.RandomFactory
* @run main StringConstructor
* @bug 4103117 4331084 4488017 4490929 6255285 6268365 8074460 8078672 8233760
* @summary Tests the BigDecimal string constructor (use -Dseed=X to set PRNG seed).
* @key randomness
*/
import java.math.*;
import java.util.Random;
import jdk.test.lib.RandomFactory;
public class StringConstructor {
public static void main(String[] args) throws Exception {
constructWithError("");
constructWithError("+");
constructWithError("-");
constructWithError("+e");
constructWithError("-e");
constructWithError("e+");
constructWithError("1.-0");
constructWithError(".-123");
constructWithError("-");
constructWithError("--1.1");
constructWithError("-+1.1");
constructWithError("+-1.1");
constructWithError("1-.1");
constructWithError("1+.1");
constructWithError("1.111+1");
constructWithError("1.111-1");
constructWithError("11.e+");
constructWithError("11.e-");
constructWithError("11.e+-");
constructWithError("11.e-+");
constructWithError("11.e-+1");
constructWithError("11.e+-1");
// Range checks
constructWithError("1e"+Integer.MIN_VALUE);
constructWithError("10e"+Integer.MIN_VALUE);
constructWithError("0.01e"+Integer.MIN_VALUE);
constructWithError("1e"+((long)Integer.MIN_VALUE-1));
leadingExponentZeroTest();
nonAsciiZeroTest();
/* These BigDecimals produce a string with an exponent > Integer.MAX_VALUE */
roundtripWithAbnormalExponent(BigDecimal.valueOf(10, Integer.MIN_VALUE));
roundtripWithAbnormalExponent(BigDecimal.valueOf(Long.MIN_VALUE, Integer.MIN_VALUE));
roundtripWithAbnormalExponent(new BigDecimal(new BigInteger("1" + "0".repeat(100)), Integer.MIN_VALUE));
/* These Strings have an exponent > Integer.MAX_VALUE */
roundtripWithAbnormalExponent("1.0E+2147483649");
roundtripWithAbnormalExponent("-9.223372036854775808E+2147483666");
roundtripWithAbnormalExponent("1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000E+2147483748");
// Roundtrip tests
Random random = RandomFactory.getRandom();
for (int i=0; i<100; i++) {
int size = random.nextInt(100) + 1;
BigInteger bi = new BigInteger(size, random);
if (random.nextBoolean())
bi = bi.negate();
int decimalLength = bi.toString().length();
int scale = random.nextInt(decimalLength);
BigDecimal bd = new BigDecimal(bi, scale);
String bdString = bd.toString();
// System.err.println("bi" + bi.toString() + "\tscale " + scale);
// System.err.println("bd string: " + bdString);
BigDecimal bdDoppel = new BigDecimal(bdString);
if (!bd.equals(bdDoppel)) {
System.err.println("bd string: scale: " + bd.scale() +
"\t" + bdString);
System.err.println("bd doppel: scale: " + bdDoppel.scale() +
"\t" + bdDoppel.toString());
throw new RuntimeException("String constructor failure.");
}
}
}
private static void roundtripWithAbnormalExponent(BigDecimal bd) {
if (!bd.equals(new BigDecimal(bd.toString()))) {
throw new RuntimeException("Abnormal exponent roundtrip failure");
}
}
private static void roundtripWithAbnormalExponent(String s) {
if (!s.equals(new BigDecimal(s).toString())) {
throw new RuntimeException("Abnormal exponent roundtrip failure");
}
}
/*
* Verify precision is set properly if the significand has
* non-ASCII leading zeros.
*/
private static void nonAsciiZeroTest() {
String values[] = {
"00004e5",
"\u0660\u0660\u0660\u06604e5",
};
BigDecimal expected = new BigDecimal("4e5");
for(String s : values) {
BigDecimal tmp = new BigDecimal(s);
// System.err.println("Testing " + s);
if (! expected.equals(tmp) || tmp.precision() != 1) {
System.err.println("Bad conversion of " + s + "got " +
tmp + "precision = " + tmp.precision());
throw new RuntimeException("String constructor failure.");
}
}
}
private static void leadingExponentZeroTest() {
BigDecimal twelve = new BigDecimal("12");
BigDecimal onePointTwo = new BigDecimal("1.2");
String start = "1.2e0";
String end = "1";
String middle = "";
// Test with more excess zeros than the largest number of
// decimal digits needed to represent a long
int limit = ((int)Math.log10(Long.MAX_VALUE)) + 6;
for(int i = 0; i < limit; i++, middle += "0") {
String t1 = start + middle;
String t2 = t1 + end;
// System.out.println(i + "\t" + t1 + "\t" + t2);
testString(t1, onePointTwo);
testString(t2, twelve);
}
}
private static void testString(String s, BigDecimal expected) {
testString0(s, expected);
testString0(switchZero(s), expected);
}
private static void testString0(String s, BigDecimal expected) {
if (!expected.equals(new BigDecimal(s)))
throw new RuntimeException(s + " is not equal to " + expected);
}
private static String switchZero(String s) {
return s.replace('0', '\u0660'); // Arabic-Indic zero
}
private static void constructWithError(String badString) {
try {
BigDecimal d = new BigDecimal(badString);
throw new RuntimeException(badString + " accepted");
} catch(NumberFormatException e) {
}
}
}

View file

@ -0,0 +1,94 @@
/*
* Copyright (c) 2003, 2025, 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.
*
* 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.
*/
/*
* @test
* @bug 4108852
* @summary A few tests of stripTrailingZeros
* @run main StrippingZerosTest
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox -XX:AutoBoxCacheMax=20000 StrippingZerosTest
*/
import java.math.*;
public class StrippingZerosTest {
public static void main(String argv[]) {
BigDecimal [][] testCases = {
{new BigDecimal("1.00000"), new BigDecimal("1")},
{new BigDecimal("1.000"), new BigDecimal("1")},
{new BigDecimal("1"), new BigDecimal("1")},
{new BigDecimal("0.1234"), new BigDecimal("0.1234")},
{new BigDecimal("0.12340"), new BigDecimal("0.1234")},
{new BigDecimal("0.12340000000"), new BigDecimal("0.1234")},
{new BigDecimal("1234.5678"), new BigDecimal("1234.5678")},
{new BigDecimal("1234.56780"), new BigDecimal("1234.5678")},
{new BigDecimal("1234.567800000"), new BigDecimal("1234.5678")},
{new BigDecimal("0"), new BigDecimal("0")},
{new BigDecimal("0e2"), BigDecimal.ZERO},
{new BigDecimal("0e-2"), BigDecimal.ZERO},
{new BigDecimal("0e42"), BigDecimal.ZERO},
{new BigDecimal("+0e42"), BigDecimal.ZERO},
{new BigDecimal("-0e42"), BigDecimal.ZERO},
{new BigDecimal("0e-42"), BigDecimal.ZERO},
{new BigDecimal("+0e-42"), BigDecimal.ZERO},
{new BigDecimal("-0e-42"), BigDecimal.ZERO},
{new BigDecimal("0e-2"), BigDecimal.ZERO},
{new BigDecimal("0e100"), BigDecimal.ZERO},
{new BigDecimal("0e-100"), BigDecimal.ZERO},
{new BigDecimal("10"), new BigDecimal("1e1")},
{new BigDecimal("20"), new BigDecimal("2e1")},
{new BigDecimal("100"), new BigDecimal("1e2")},
{new BigDecimal("1000000000"), new BigDecimal("1e9")},
{new BigDecimal("100000000e1"), new BigDecimal("1e9")},
{new BigDecimal("10000000e2"), new BigDecimal("1e9")},
{new BigDecimal("1000000e3"), new BigDecimal("1e9")},
{new BigDecimal("100000e4"), new BigDecimal("1e9")},
// BD value which larger than Long.MaxValue
{new BigDecimal("1.0000000000000000000000000000"), new BigDecimal("1")},
{new BigDecimal("-1.0000000000000000000000000000"), new BigDecimal("-1")},
{new BigDecimal("1.00000000000000000000000000001"), new BigDecimal("1.00000000000000000000000000001")},
{new BigDecimal("1000000000000000000000000000000e4"), new BigDecimal("1e34")},
};
for(int i = 0; i < testCases.length; i++) {
if (!(testCases[i][0]).stripTrailingZeros().equals(testCases[i][1])) {
throw new RuntimeException("For input " + testCases[i][0].toString() +
" did not received expected result " +
testCases[i][1].toString() + ", got " +
testCases[i][0].stripTrailingZeros());
}
testCases[i][0] = testCases[i][0].negate();
testCases[i][1] = testCases[i][1].negate();
if (!(testCases[i][0]).stripTrailingZeros().equals(testCases[i][1])) {
throw new RuntimeException("For input " + testCases[i][0].toString() +
" did not received expected result " +
testCases[i][1].toString() + ", got " +
testCases[i][0].stripTrailingZeros());
}
}
}
}

View file

@ -0,0 +1,131 @@
/*
* Copyright (c) 2004, 2025, 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.
*
* 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.
*/
/*
* @test
* @bug 4984872 8318915
* @summary Basic tests of toPlainString method
* @run main ToPlainStringTests
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox -XX:AutoBoxCacheMax=20000 ToPlainStringTests
*/
import java.math.*;
public class ToPlainStringTests {
public static void main(String argv[]) {
String [][] testCases = {
{"0", "0"},
{"1", "1"},
{"10", "10"},
{"2e1", "20"},
{"3e2", "300"},
{"4e3", "4000"},
{"5e4", "50000"},
{"6e5", "600000"},
{"7e6", "7000000"},
{"8e7", "80000000"},
{"9e8", "900000000"},
{"1e9", "1000000000"},
{".0", "0.0"},
{".1", "0.1"},
{".10", "0.10"},
{"1e-1", "0.1"},
{"1e-1", "0.1"},
{"2e-2", "0.02"},
{"3e-3", "0.003"},
{"4e-4", "0.0004"},
{"5e-5", "0.00005"},
{"6e-6", "0.000006"},
{"7e-7", "0.0000007"},
{"8e-8", "0.00000008"},
{"9e-9", "0.000000009"},
{"9000e-12", "0.000000009000"},
{"9000e-22", "0.0000000000000000009000"},
{"12345678901234567890", "12345678901234567890"},
{"12345678901234567890e22", "123456789012345678900000000000000000000000"},
{"12345678901234567890e-22", "0.0012345678901234567890"},
{"12345e-1", "1234.5"},
{"12345e-2", "123.45"},
{"12345e-3", "12.345"},
{"12345e-4", "1.2345"},
};
int errors = 0;
for(String[] testCase: testCases) {
BigDecimal bd = new BigDecimal(testCase[0]);
String s;
if (!(s=bd.toPlainString()).equals(testCase[1])) {
errors++;
System.err.println("Unexpected plain result ``" +
s + "'' from BigDecimal " +
bd);
}
bd = new BigDecimal("-"+testCase[0]);
if (bd.signum()!=0 && !(s=(bd.toPlainString())).equals("-"+testCase[1])) {
errors++;
System.err.println("Unexpected plain result ``" +
s + "'' from BigDecimal " +
bd);
}
}
String[] failingCases = {
"1E-" + (Integer.MAX_VALUE - 0), // MAX_VALUE + 2 chars
"1E-" + (Integer.MAX_VALUE - 1), // MAX_VALUE + 1 chars
"-1E-" + (Integer.MAX_VALUE - 0), // MAX_VALUE + 3 chars
"-1E-" + (Integer.MAX_VALUE - 1), // MAX_VALUE + 2 chars
"-1E-" + (Integer.MAX_VALUE - 2), // MAX_VALUE + 1 chars
"123456789E-" + (Integer.MAX_VALUE - 0), // MAX_VALUE + 2 chars
"123456789E-" + (Integer.MAX_VALUE - 1), // MAX_VALUE + 1 chars
"-123456789E-" + (Integer.MAX_VALUE - 0), // MAX_VALUE + 3 chars
"-123456789E-" + (Integer.MAX_VALUE - 1), // MAX_VALUE + 2 chars
"-123456789E-" + (Integer.MAX_VALUE - 2), // MAX_VALUE + 1 chars
"1E" + Integer.MAX_VALUE, // MAX_VALUE + 1 chars
"123456789E" + Integer.MAX_VALUE, // MAX_VALUE + 9 chars
"-1E" + Integer.MAX_VALUE, // MAX_VALUE + 2 chars
"-123456789E" + Integer.MAX_VALUE, // MAX_VALUE + 10 chars
};
/* We expect pre-emptive OutOfMemoryErrors, nothing else */
for (String failingCase : failingCases) {
try {
new BigDecimal(failingCase).toPlainString();
} catch (OutOfMemoryError expected) {
continue;
} catch (Throwable ignored) {
}
++errors;
}
if(errors > 0)
throw new RuntimeException(errors + " errors during run.");
}
}

View file

@ -0,0 +1,74 @@
/*
* Copyright (c) 2025, 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.
*
* 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.
*/
/*
* @test
* @bug 8356709
* @summary Test Double.toString(double)
* @run junit ValueOfDouble
*/
import org.junit.jupiter.api.Test;
import java.math.BigDecimal;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class ValueOfDouble {
private static final String DIGITS = "1234567000003456789"; // Enough digits to fill a long
@Test
public void testValueOfDouble() {
checkValue(0.0);
checkValue(-0.0);
checkValue(Math.PI);
checkValue(-Math.PI);
checkValue(Double.MAX_VALUE);
checkValue(Double.MIN_VALUE);
checkValue(1e-44); // Lots of digits with lots of 9s
for (int prec = 1; prec < DIGITS.length(); prec++) {
String prefix = DIGITS.substring(0, prec);
for (int exp = -30; exp < 30; exp++) {
double value = Double.parseDouble(prefix + "e" + exp);
checkValue(value);
checkValue(-value);
}
}
}
private static void checkValue(double value) {
BigDecimal expected = new BigDecimal(Double.toString(value));
assertEquals(expected, BigDecimal.valueOf(value));
}
@Test
public void testExceptions() {
assertThrows(NumberFormatException.class, () -> BigDecimal.valueOf(Double.NaN));
assertThrows(NumberFormatException.class, () -> BigDecimal.valueOf(Double.POSITIVE_INFINITY));
assertThrows(NumberFormatException.class, () -> BigDecimal.valueOf(Double.NEGATIVE_INFINITY));
}
}

View file

@ -0,0 +1,476 @@
/*
* Copyright (c) 2003, 2025, 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.
*
* 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.
*/
/*
* @test
* @bug 4902952 4905407 4916149 8057793
* @summary Tests that the scale of zero is propagated properly and has the
* proper effect and that setting the scale to zero does not mutate the
* BigDecimal.
*/
import java.math.*;
import java.util.*;
public class ZeroScalingTests {
static MathContext longEnough = new MathContext(50, RoundingMode.UNNECESSARY);
static BigDecimal[] zeros = new BigDecimal[23];
static {
for(int i = 0; i < 21; i++) {
zeros[i] = new BigDecimal(BigInteger.ZERO, i-10);
}
zeros[21] = new BigDecimal(BigInteger.ZERO, Integer.MIN_VALUE);
zeros[22] = new BigDecimal(BigInteger.ZERO, Integer.MAX_VALUE);
}
static BigDecimal element = BigDecimal.valueOf(100, -2);
static MathContext contexts[] = {
new MathContext(0, RoundingMode.UNNECESSARY),
new MathContext(100, RoundingMode.UNNECESSARY),
new MathContext(5, RoundingMode.UNNECESSARY),
new MathContext(4, RoundingMode.UNNECESSARY),
new MathContext(3, RoundingMode.UNNECESSARY),
new MathContext(2, RoundingMode.UNNECESSARY),
new MathContext(1, RoundingMode.UNNECESSARY),
};
static int addTests() {
int failures = 0;
for(BigDecimal zero1: zeros) {
for(BigDecimal zero2: zeros) {
BigDecimal expected = new BigDecimal(BigInteger.ZERO,
Math.max(zero1.scale(), zero2.scale()));
BigDecimal result;
if(! (result=zero1.add(zero2)).equals(expected) ) {
failures++;
System.err.println("For classic exact add, expected scale of " +
expected.scale() + "; got " +
result.scale() + ".");
}
if(! (result=zero1.add(zero2, MathContext.UNLIMITED)).equals(expected) ) {
failures++;
System.err.println("For UNLIMITED math context add," +
" expected scale of " +
expected.scale() + "; got " +
result.scale() + ".");
}
if(! (result=zero1.add(zero2, longEnough)).equals(expected) ) {
failures++;
System.err.println("For longEnough math context add," +
" expected scale of " +
expected.scale() + "; got " +
result.scale() + ".");
}
}
}
// Test effect of adding zero to a nonzero value.
for (MathContext mc: contexts) {
for (BigDecimal zero: zeros) {
if (Math.abs((long)zero.scale()) < 100 ) {
int preferredScale = Math.max(zero.scale(), element.scale());
if (mc.getPrecision() != 0) {
if (preferredScale < -4 )
preferredScale = -4;
else if (preferredScale > -(5 - mc.getPrecision())) {
preferredScale = -(5 - mc.getPrecision());
}
}
/*
System.err.println("\n " + element + " +\t" + zero + " =\t" + result);
System.err.println("scales" + element.scale() + " \t" + zero.scale() +
" \t " + result.scale() + "\t precison = " + mc.getPrecision());
System.err.println("expected scale = " + preferredScale);
*/
BigDecimal result = element.add(zero, mc);
if (result.scale() != preferredScale ||
result.compareTo(element) != 0) {
failures++;
System.err.println("Expected scale " + preferredScale +
" result scale was " + result.scale() +
" ; value was " + result);
}
result = zero.add(element, mc);
if (result.scale() != preferredScale ||
result.compareTo(element) != 0) {
failures++;
System.err.println("Expected scale " + preferredScale +
" result scale was " + result.scale() +
" ; value was " + result);
}
result = element.negate().add(zero, mc);
if (result.scale() != preferredScale ||
result.compareTo(element.negate()) != 0) {
failures++;
System.err.println("Expected scale " + preferredScale +
" result scale was " + result.scale() +
" ; value was " + result);
}
result = zero.add(element.negate(), mc);
if (result.scale() != preferredScale ||
result.compareTo(element.negate()) != 0) {
failures++;
System.err.println("Expected scale " + preferredScale +
" result scale was " + result.scale() +
" ; value was " + result);
}
}
}
}
return failures;
}
static int subtractTests() {
int failures = 0;
for(BigDecimal zero1: zeros) {
for(BigDecimal zero2: zeros) {
BigDecimal expected = new BigDecimal(BigInteger.ZERO,
Math.max(zero1.scale(), zero2.scale()));
BigDecimal result;
if(! (result=zero1.subtract(zero2)).equals(expected) ) {
failures++;
System.err.println("For classic exact subtract, expected scale of " +
expected.scale() + "; got " +
result.scale() + ".");
}
if(! (result=zero1.subtract(zero2, MathContext.UNLIMITED)).equals(expected) ) {
failures++;
System.err.println("For UNLIMITED math context subtract," +
" expected scale of " +
expected.scale() + "; got " +
result.scale() + ".");
}
if(! (result=zero1.subtract(zero2, longEnough)).equals(expected) ) {
failures++;
System.err.println("For longEnough math context subtract," +
" expected scale of " +
expected.scale() + "; got " +
result.scale() + ".");
}
}
}
// Test effect of adding zero to a nonzero value.
for (MathContext mc: contexts) {
for (BigDecimal zero: zeros) {
if (Math.abs((long)zero.scale()) < 100 ) {
int preferredScale = Math.max(zero.scale(), element.scale());
if (mc.getPrecision() != 0) {
if (preferredScale < -4 )
preferredScale = -4;
else if (preferredScale > -(5 - mc.getPrecision())) {
preferredScale = -(5 - mc.getPrecision());
}
}
/*
System.err.println("\n " + element + " +\t" + zero + " =\t" + result);
System.err.println("scales" + element.scale() + " \t" + zero.scale() +
" \t " + result.scale() + "\t precison = " + mc.getPrecision());
System.err.println("expected scale = " + preferredScale);
*/
BigDecimal result = element.subtract(zero, mc);
if (result.scale() != preferredScale ||
result.compareTo(element) != 0) {
failures++;
System.err.println("Expected scale " + preferredScale +
" result scale was " + result.scale() +
" ; value was " + result);
}
result = zero.subtract(element, mc);
if (result.scale() != preferredScale ||
result.compareTo(element.negate()) != 0) {
failures++;
System.err.println("Expected scale " + preferredScale +
" result scale was " + result.scale() +
" ; value was " + result);
}
result = element.negate().subtract(zero, mc);
if (result.scale() != preferredScale ||
result.compareTo(element.negate()) != 0) {
failures++;
System.err.println("Expected scale " + preferredScale +
" result scale was " + result.scale() +
" ; value was " + result);
}
result = zero.subtract(element.negate(), mc);
if (result.scale() != preferredScale ||
result.compareTo(element) != 0) {
failures++;
System.err.println("Expected scale " + preferredScale +
" result scale was " + result.scale() +
" ; value was " + result);
}
}
}
}
return failures;
}
static int multiplyTests() {
int failures = 0;
BigDecimal ones[] = {
BigDecimal.valueOf(1, 0),
BigDecimal.valueOf(10, 1),
BigDecimal.valueOf(1000, 3),
BigDecimal.valueOf(100000000, 8),
};
List<BigDecimal> values = new LinkedList<BigDecimal>();
values.addAll(Arrays.asList(zeros));
values.addAll(Arrays.asList(ones));
for(BigDecimal zero1: zeros) {
for(BigDecimal value: values) {
BigDecimal expected = new BigDecimal(BigInteger.ZERO,
(int)Math.min(Math.max((long)zero1.scale()+value.scale(),
Integer.MIN_VALUE ),
Integer.MAX_VALUE ) );
BigDecimal result;
if(! (result=zero1.multiply(value)).equals(expected) ) {
failures++;
System.err.println("For classic exact multiply, expected scale of " +
expected.scale() + "; got " +
result.scale() + ".");
}
if(! (result=zero1.multiply(value, MathContext.UNLIMITED)).equals(expected) ) {
failures++;
System.err.println("For UNLIMITED math context multiply," +
" expected scale of " +
expected.scale() + "; got " +
result.scale() + ".");
}
if(! (result=zero1.multiply(value, longEnough)).equals(expected) ) {
failures++;
System.err.println("For longEnough math context multiply," +
" expected scale of " +
expected.scale() + "; got " +
result.scale() + ".");
}
}
}
return failures;
}
static int divideTests() {
int failures = 0;
BigDecimal [] ones = {
BigDecimal.valueOf(1, 0),
BigDecimal.valueOf(10, -1),
BigDecimal.valueOf(100, -2),
BigDecimal.valueOf(1000, -3),
BigDecimal.valueOf(1000000, -5),
};
for(BigDecimal one: ones) {
for(BigDecimal zero: zeros) {
BigDecimal expected = new BigDecimal(BigInteger.ZERO,
(int)Math.min(Math.max((long)zero.scale() - one.scale(),
Integer.MIN_VALUE ),
Integer.MAX_VALUE ) );
BigDecimal result;
if(! (result=zero.divide(one)).equals(expected) ) {
failures++;
System.err.println("For classic exact divide, expected scale of " +
expected.scale() + "; got " +
result.scale() + ".");
}
if(! (result=zero.divide(one, MathContext.UNLIMITED)).equals(expected) ) {
failures++;
System.err.println("For UNLIMITED math context divide," +
" expected scale of " +
expected.scale() + "; got " +
result.scale() + ".");
}
if(! (result=zero.divide(one, longEnough)).equals(expected) ) {
failures++;
System.err.println("For longEnough math context divide," +
" expected scale of " +
expected.scale() + "; got " +
result.scale() + ".");
}
}
}
return failures;
}
static int setScaleTests() {
int failures = 0;
int scales[] = {
Integer.MIN_VALUE,
Integer.MIN_VALUE+1,
-10000000,
-3,
-2,
-1,
0,
1,
2,
3,
10,
10000000,
Integer.MAX_VALUE-1,
Integer.MAX_VALUE
};
for(BigDecimal zero: zeros) {
for(int scale: scales) {
try {
BigDecimal bd = zero.setScale(scale);
}
catch (ArithmeticException e) {
failures++;
System.err.println("Exception when trying to set a scale of " + scale +
" on " + zero);
}
}
}
return failures;
}
static int toEngineeringStringTests() {
int failures = 0;
String [][] testCases = {
{"0E+10", "0.00E+12"},
{"0E+9", "0E+9"},
{"0E+8", "0.0E+9"},
{"0E+7", "0.00E+9"},
{"0E-10", "0.0E-9"},
{"0E-9", "0E-9"},
{"0E-8", "0.00E-6"},
{"0E-7", "0.0E-6"},
};
for(String[] testCase: testCases) {
BigDecimal bd = new BigDecimal(testCase[0]);
String result = bd.toEngineeringString();
if (!result.equals(testCase[1]) ||
!bd.equals(new BigDecimal(result))) {
failures++;
System.err.println("From input ``" + testCase[0] + ",'' " +
" bad engineering string output ``" + result +
"''; expected ``" + testCase[1] + ".''");
}
}
return failures;
}
static int ulpTests() {
int failures = 0;
for(BigDecimal zero: zeros) {
BigDecimal result;
BigDecimal expected = BigDecimal.valueOf(1, zero.scale());
if (! (result=zero.ulp()).equals(expected) ) {
failures++;
System.err.println("Unexpected ulp value for zero value " +
zero + "; expected " + expected +
", got " + result);
}
}
return failures;
}
static int setScaleDoesNotMutateTest() {
BigDecimal total = new BigDecimal("258815507198903607775511093103396443816569106750031264155319238473795838680758514810110764742309284477206138527975952150289602995045050194333030191178778772026538699925775139201970526695485362661420908248887297829319881475178467494779683293036572059595504702727301324759997409522995072582369210284334718757260859794972695026582432867589093687280300148141501712013226636373167978223780290547640482160818746599330924736802844173226042389174403401903999447463440670236056324929325189403433689"
+ ".426167432065785331444814035799717606745777287606858873045971898862329763544687891847664736523584843544347118836628373041412918374550458884706686730726101338872517021688769782894793734049819222924171842793485919753186993388451909096042127903835765393729547730953942175461146061715108701615615142134282261293656760570061554783195726716403304101469782303957325142638493327692352838806741611887655695029948975509680496573999174402058593454203190963443179532640446352828089016874853634851387762579319853267317320515941105912189838719919259277721994880193541634872882180184303434360412344059435559680494807415573269199203376126242271766939666939316648575065702750502798973418978204972336924254702551350654650573582614211506856383897692911422458286912085339575875324832979140870119455620532272318122103640233069115700020760625493816902806241630788230268031695140687964931377988962507263990468276009750998066442971308866347136022907166625330623130307555914930120150437900510530537258665172619821272937026713977709974434967165159545592482710663639966781678268622620229577009317698254134914742098420792313931843709810905414336383757407675429663714210967924767434203021205270369316797752411974617662200898086335322218191674846795163102021505555508444216708745911194321674887527227200297039471799580744303346354057273540730643842091810899490590914195225087593013834388801018488174855060306804024894292757613618190472234110859436472645203753139820658279559340251226992556744343475086923568365637919479462424794554522865559888240039662899509652221329892034706445253487898044421278283079233226845124525434586324657471286953226255430662125870993375281512713207125720748163498642795960457639954616530163959004770092547297392499137383176609646505351001304840762905826237024982330597805063521162285806541220110524989649256399233792799406995068469271941269511818994954109392839548141262324660472253632382325038836831429045617036015122388070240133760858500132713255407855625837956886349324981003917084922808187223285051144454915441134217743066575863563572152133978905444998209075763950909784148142018992367290485890072303179512881131769414783097454103103347826517701720263541869335631166977965013552647906729408522950996105479525445916501155305220090853891226367184989434453290788068397817927893708837722255115237672194162924260945492012622891770365546831236789867922136747819364833843397165107825773447549885351449899330007200651144003961228091210630807333236718793283427788965479074476288255387824982443633190938302785760754436525586544523339170400053128503337395428393881357669568532722167493096151221381017320147344991331421789379785964440840684363041795410525097564979585773948558651896834067324427900848255265001498890329859444233861478388742393060996236783742654761350763876989363052609107226398858310051497856931093693697981165801539060516895227818925342535261227134364063673285588256280386915163875872231395348293505967057794409379709079685798908660258077792158532257603211711587587586356431658240229896344639704");
if (total.setScale(0, RoundingMode.DOWN).equals(total.setScale(0, RoundingMode.DOWN))) {
return 0;
} else {
return 1;
}
}
public static void main(String argv[]) {
int failures = 0;
failures += addTests();
failures += subtractTests();
failures += multiplyTests();
failures += divideTests();
failures += setScaleTests();
failures += toEngineeringStringTests();
failures += ulpTests();
failures += setScaleDoesNotMutateTest();
if (failures > 0 ) {
throw new RuntimeException("Incurred " + failures + " failures" +
" testing the preservation of zero scales.");
}
}
}