blob: a9a796c8742dd185cf23ada4005eb4c8d2129a67 [file] [log] [blame]
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package libcore.java.math;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.Locale;
import junit.framework.TestCase;
public final class BigDecimalTest extends TestCase {
public void testGetPrecision() {
assertPrecision(1, "0");
assertPrecision(1, "0.9");
assertPrecision(16, "0.9999999999999999");
assertPrecision(16, "9999999999999999");
assertPrecision(19, "1000000000000000000");
assertPrecision(19, "1000000000000000001");
assertPrecision(19, "-1000000000000000001");
assertPrecision(19, "-1000000000000000000");
String tenNines = "9999999999";
String fiftyNines = tenNines + tenNines + tenNines + tenNines + tenNines;
assertPrecision(10, "0." + tenNines);
assertPrecision(50, "0." + fiftyNines);
assertPrecision(250, "0." + fiftyNines + fiftyNines + fiftyNines + fiftyNines + fiftyNines);
assertPrecision(10, tenNines);
assertPrecision(50, fiftyNines);
assertPrecision(250, fiftyNines + fiftyNines + fiftyNines + fiftyNines + fiftyNines);
// test these special cases because we know precision() uses longs internally
String maxLong = Long.toString(Long.MAX_VALUE);
assertPrecision(maxLong.length(), maxLong);
String minLong = Long.toString(Long.MIN_VALUE);
assertPrecision(minLong.length() - 1, minLong);
}
private void assertPrecision(int expectedPrecision, String value) {
BigDecimal parsed = new BigDecimal(value);
assertEquals("Unexpected precision for parsed value " + value,
expectedPrecision, parsed.precision());
BigDecimal computed = parsed.divide(BigDecimal.ONE);
assertEquals("Unexpected precision for computed value " + value,
expectedPrecision, computed.precision());
}
public void testRound() {
BigDecimal bigDecimal = new BigDecimal("0.999999999999999");
BigDecimal rounded = bigDecimal.round(new MathContext(2, RoundingMode.FLOOR));
assertEquals("0.99", rounded.toString());
}
// https://code.google.com/p/android/issues/detail?id=43480
public void testPrecisionFromString() {
BigDecimal a = new BigDecimal("-0.011111111111111111111");
BigDecimal b = a.multiply(BigDecimal.ONE);
assertEquals("-0.011111111111111111111", a.toString());
assertEquals("-0.011111111111111111111", b.toString());
assertEquals(20, a.precision());
assertEquals(20, b.precision());
assertEquals(21, a.scale());
assertEquals(21, b.scale());
assertEquals("-11111111111111111111", a.unscaledValue().toString());
assertEquals("-11111111111111111111", b.unscaledValue().toString());
assertEquals(a, b);
assertEquals(b, a);
assertEquals(0, a.subtract(b).signum());
assertEquals(0, a.compareTo(b));
}
public void testPrecisionFromString_simplePowersOfTen() {
assertEquals(new BigDecimal(BigInteger.valueOf(-10), 1), new BigDecimal("-1.0"));
assertEquals(new BigDecimal(BigInteger.valueOf(-1), 1), new BigDecimal("-0.1"));
assertEquals(new BigDecimal(BigInteger.valueOf(-1), -1), new BigDecimal("-1E+1"));
assertEquals(new BigDecimal(BigInteger.valueOf(10), 1), new BigDecimal("1.0"));
assertEquals(new BigDecimal(BigInteger.valueOf(1), 0), new BigDecimal("1"));
assertFalse(new BigDecimal("1.0").equals(new BigDecimal("1")));
}
// https://code.google.com/p/android/issues/detail?id=54580
public void test54580() {
BigDecimal a = new BigDecimal("1.200002");
assertEquals("1.200002", a.toPlainString());
assertEquals("1.20", a.abs(new MathContext(3,RoundingMode.HALF_UP)).toPlainString());
assertEquals("1.200002", a.toPlainString());
}
// https://code.google.com/p/android/issues/detail?id=191227
public void test191227() {
BigDecimal zero = BigDecimal.ZERO;
zero = zero.setScale(2, RoundingMode.HALF_EVEN);
BigDecimal other = BigDecimal.valueOf(999999998000000001.00);
other = other.setScale(2, RoundingMode.HALF_EVEN);
assertFalse(zero.equals(other));
assertFalse(other.equals(zero));
}
private static void checkDivide(String expected, long n, long d, int scale, RoundingMode rm) {
assertEquals(String.format(Locale.US, "%d/%d [%d, %s]", n, d, scale, rm.name()),
new BigDecimal(expected),
new BigDecimal(n).divide(new BigDecimal(d), scale, rm));
}
public void testDivideRounding() {
// checkDivide(expected, dividend, divisor, scale, roundingMode)
checkDivide("0", 1, Long.MIN_VALUE, 0, RoundingMode.DOWN);
checkDivide("-1", 1, Long.MIN_VALUE, 0, RoundingMode.UP);
checkDivide("-1", 1, Long.MIN_VALUE, 0, RoundingMode.FLOOR);
checkDivide("0", 1, Long.MIN_VALUE, 0, RoundingMode.CEILING);
checkDivide("0", 1, Long.MIN_VALUE, 0, RoundingMode.HALF_EVEN);
checkDivide("0", 1, Long.MIN_VALUE, 0, RoundingMode.HALF_UP);
checkDivide("0", 1, Long.MIN_VALUE, 0, RoundingMode.HALF_DOWN);
checkDivide("1", Long.MAX_VALUE, Long.MAX_VALUE / 2 + 1, 0, RoundingMode.DOWN);
checkDivide("2", Long.MAX_VALUE, Long.MAX_VALUE / 2, 0, RoundingMode.DOWN);
checkDivide("0.50", Long.MAX_VALUE / 2, Long.MAX_VALUE, 2, RoundingMode.HALF_UP);
checkDivide("0.50", Long.MIN_VALUE / 2, Long.MIN_VALUE, 2, RoundingMode.HALF_UP);
checkDivide("0.5000", Long.MIN_VALUE / 2, Long.MIN_VALUE, 4, RoundingMode.HALF_UP);
// (-2^62 + 1) / (-2^63) = (2^62 - 1) / 2^63 = 0.5 - 2^-63
checkDivide("0", Long.MIN_VALUE / 2 + 1, Long.MIN_VALUE, 0, RoundingMode.HALF_UP);
checkDivide("1", Long.MIN_VALUE / 2, Long.MIN_VALUE, 0, RoundingMode.HALF_UP);
checkDivide("0", Long.MIN_VALUE / 2, Long.MIN_VALUE, 0, RoundingMode.HALF_DOWN);
// (-2^62 - 1) / (-2^63) = (2^62 + 1) / 2^63 = 0.5 + 2^-63
checkDivide("1", Long.MIN_VALUE / 2 - 1, Long.MIN_VALUE, 0, RoundingMode.HALF_DOWN);
}
/**
* Test a bunch of pairings with even/odd dividend and divisor whose
* result is near +/- 0.5.
*/
public void testDivideRounding_sign() {
// checkDivide(expected, dividend, divisor, scale, roundingMode)
// positive dividend and divisor, even/odd values
checkDivide("0", 49, 100, 0, RoundingMode.HALF_UP);
checkDivide("1", 50, 100, 0, RoundingMode.HALF_UP);
checkDivide("1", 51, 101, 0, RoundingMode.HALF_UP);
checkDivide("0", 50, 101, 0, RoundingMode.HALF_UP);
checkDivide("0", Long.MAX_VALUE / 2, Long.MAX_VALUE, 0, RoundingMode.HALF_UP);
// Same with negative dividend and divisor
checkDivide("0", -49, -100, 0, RoundingMode.HALF_UP);
checkDivide("1", -50, -100, 0, RoundingMode.HALF_UP);
checkDivide("1", -51, -101, 0, RoundingMode.HALF_UP);
checkDivide("0", -50, -101, 0, RoundingMode.HALF_UP);
checkDivide("0", -(Long.MAX_VALUE / 2), -Long.MAX_VALUE, 0, RoundingMode.HALF_UP);
// Same with negative dividend
checkDivide("0", -49, 100, 0, RoundingMode.HALF_UP);
checkDivide("-1", -50, 100, 0, RoundingMode.HALF_UP);
checkDivide("-1", -51, 101, 0, RoundingMode.HALF_UP);
checkDivide("0", -50, 101, 0, RoundingMode.HALF_UP);
checkDivide("0", -(Long.MAX_VALUE / 2), Long.MAX_VALUE, 0, RoundingMode.HALF_UP);
// Same with negative divisor
checkDivide("0", 49, -100, 0, RoundingMode.HALF_UP);
checkDivide("-1", 50, -100, 0, RoundingMode.HALF_UP);
checkDivide("-1", 51, -101, 0, RoundingMode.HALF_UP);
checkDivide("0", 50, -101, 0, RoundingMode.HALF_UP);
checkDivide("0", Long.MAX_VALUE / 2, -Long.MAX_VALUE, 0, RoundingMode.HALF_UP);
}
public void testDivideByOne() {
long[] dividends = new long[] {
Long.MIN_VALUE,
Long.MIN_VALUE + 1,
Long.MAX_VALUE,
Long.MAX_VALUE - 1,
0,
-1,
1,
10, 43, 314159265358979323L, // arbitrary values
};
for (long dividend : dividends) {
String expected = Long.toString(dividend);
checkDivide(expected, dividend, 1, 0, RoundingMode.UNNECESSARY);
}
}
/**
* Tests that Long.MIN_VALUE / -1 doesn't overflow back to Long.MIN_VALUE,
* like it would in long arithmetic.
*/
// https://code.google.com/p/android/issues/detail?id=196555
public void testDivideAvoids64bitOverflow() throws Exception {
BigDecimal minLong = new BigDecimal("-9223372036854775808");
assertEquals("9223372036854775808/(-1)",
new BigDecimal("9223372036854775808"),
minLong.divide(new BigDecimal("-1"), /* scale = */ 0, RoundingMode.UNNECESSARY));
assertEquals("922337203685477580.8/(-0.1)",
new BigDecimal("9223372036854775808"),
new BigDecimal("-922337203685477580.8")
.divide(new BigDecimal("-0.1"), /* scale = */ 0, RoundingMode.UNNECESSARY));
assertEquals("92233720368547758080/(-1E+1)",
new BigDecimal("9223372036854775808"),
new BigDecimal("-92233720368547758080")
.divide(new BigDecimal("-1E+1"), /* scale = */ 0, RoundingMode.UNNECESSARY));
assertEquals("9223372036854775808/(-10) with one decimal of precision",
new BigDecimal("922337203685477580.8"),
minLong.divide(new BigDecimal("-1E+1"), /* scale = */ 1, RoundingMode.UNNECESSARY));
// cases that request adjustment of the result scale, i.e. (diffScale != 0)
// i.e. result scale != (dividend.scale - divisor.scale)
assertEquals("9223372036854775808/(-1) with one decimal of precision",//
new BigDecimal("9223372036854775808.0"),
minLong.divide(new BigDecimal("-1"), /* scale = */ 1, RoundingMode.UNNECESSARY));
assertEquals("9223372036854775808/(-1.0)",//
new BigDecimal("9223372036854775808"),
minLong.divide(new BigDecimal("-1.0"), /* scale = */ 0, RoundingMode.UNNECESSARY));
assertEquals("9223372036854775808/(-1.0) with one decimal of precision",//
new BigDecimal("9223372036854775808.0"),
minLong.divide(new BigDecimal("-1.0"), /* scale = */ 1, RoundingMode.UNNECESSARY));
// another arbitrary calculation that results in Long.MAX_VALUE + 1
// via a different route
assertEquals("4611686018427387904/(-5E-1)",//
new BigDecimal("9223372036854775808"),
new BigDecimal("-4611686018427387904").divide(
new BigDecimal("-5E-1"), /* scale = */ 0, RoundingMode.UNNECESSARY));
}
}