• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package libcore.java.math;
18 
19 import java.math.BigDecimal;
20 import java.math.BigInteger;
21 import java.math.MathContext;
22 import java.math.RoundingMode;
23 import java.util.Locale;
24 
25 import junit.framework.TestCase;
26 
27 import static java.math.BigDecimal.valueOf;
28 
29 public final class BigDecimalTest extends TestCase {
30 
testGetPrecision()31     public void testGetPrecision() {
32         assertPrecision(1, "0");
33         assertPrecision(1, "0.9");
34         assertPrecision(16, "0.9999999999999999");
35         assertPrecision(16, "9999999999999999");
36         assertPrecision(19, "1000000000000000000");
37         assertPrecision(19, "1000000000000000001");
38         assertPrecision(19, "-1000000000000000001");
39         assertPrecision(19, "-1000000000000000000");
40 
41         String tenNines = "9999999999";
42         String fiftyNines = tenNines + tenNines + tenNines + tenNines + tenNines;
43         assertPrecision(10, "0." + tenNines);
44         assertPrecision(50, "0." + fiftyNines);
45         assertPrecision(250, "0." + fiftyNines + fiftyNines + fiftyNines + fiftyNines + fiftyNines);
46         assertPrecision(10, tenNines);
47         assertPrecision(50, fiftyNines);
48         assertPrecision(250, fiftyNines + fiftyNines + fiftyNines + fiftyNines + fiftyNines);
49 
50         // test these special cases because we know precision() uses longs internally
51         String maxLong = Long.toString(Long.MAX_VALUE);
52         assertPrecision(maxLong.length(), maxLong);
53         String minLong = Long.toString(Long.MIN_VALUE);
54         assertPrecision(minLong.length() - 1, minLong);
55     }
56 
assertPrecision(int expectedPrecision, String value)57     private void assertPrecision(int expectedPrecision, String value) {
58         BigDecimal parsed = new BigDecimal(value);
59         assertEquals("Unexpected precision for parsed value " + value,
60                 expectedPrecision, parsed.precision());
61 
62         BigDecimal computed = parsed.divide(BigDecimal.ONE);
63         assertEquals("Unexpected precision for computed value " + value,
64                 expectedPrecision, computed.precision());
65     }
66 
testRound()67     public void testRound() {
68         BigDecimal bigDecimal = new BigDecimal("0.999999999999999");
69         BigDecimal rounded = bigDecimal.round(new MathContext(2, RoundingMode.FLOOR));
70         assertEquals("0.99", rounded.toString());
71     }
72 
73     // https://code.google.com/p/android/issues/detail?id=43480
testPrecisionFromString()74     public void testPrecisionFromString() {
75         BigDecimal a = new BigDecimal("-0.011111111111111111111");
76         BigDecimal b = a.multiply(BigDecimal.ONE);
77 
78         assertEquals("-0.011111111111111111111", a.toString());
79         assertEquals("-0.011111111111111111111", b.toString());
80 
81         assertEquals(20, a.precision());
82         assertEquals(20, b.precision());
83 
84         assertEquals(21, a.scale());
85         assertEquals(21, b.scale());
86 
87         assertEquals("-11111111111111111111", a.unscaledValue().toString());
88         assertEquals("-11111111111111111111", b.unscaledValue().toString());
89 
90         assertEquals(a, b);
91         assertEquals(b, a);
92 
93         assertEquals(0, a.subtract(b).signum());
94         assertEquals(0, a.compareTo(b));
95     }
96 
testPrecisionFromString_simplePowersOfTen()97     public void testPrecisionFromString_simplePowersOfTen() {
98         assertEquals(new BigDecimal(BigInteger.valueOf(-10), 1), new BigDecimal("-1.0"));
99         assertEquals(new BigDecimal(BigInteger.valueOf(-1), 1), new BigDecimal("-0.1"));
100         assertEquals(new BigDecimal(BigInteger.valueOf(-1), -1), new BigDecimal("-1E+1"));
101 
102         assertEquals(new BigDecimal(BigInteger.valueOf(10), 1), new BigDecimal("1.0"));
103         assertEquals(new BigDecimal(BigInteger.valueOf(1), 0), new BigDecimal("1"));
104         assertFalse(new BigDecimal("1.0").equals(new BigDecimal("1")));
105     }
106 
107     // https://code.google.com/p/android/issues/detail?id=54580
test54580()108     public void test54580() {
109         BigDecimal a = new BigDecimal("1.200002");
110         assertEquals("1.200002", a.toPlainString());
111         assertEquals("1.20", a.abs(new MathContext(3,RoundingMode.HALF_UP)).toPlainString());
112         assertEquals("1.200002", a.toPlainString());
113     }
114 
115     // https://code.google.com/p/android/issues/detail?id=191227
test191227()116     public void test191227() {
117         BigDecimal zero = BigDecimal.ZERO;
118         zero = zero.setScale(2, RoundingMode.HALF_EVEN);
119 
120         BigDecimal other = valueOf(999999998000000001.00);
121         other = other.setScale(2, RoundingMode.HALF_EVEN);
122 
123         assertFalse(zero.equals(other));
124         assertFalse(other.equals(zero));
125     }
126 
checkDivide(String expected, long n, long d, int scale, RoundingMode rm)127     private static void checkDivide(String expected, long n, long d, int scale, RoundingMode rm) {
128         assertEquals(String.format(Locale.US, "%d/%d [%d, %s]", n, d, scale, rm.name()),
129                 new BigDecimal(expected),
130                 new BigDecimal(n).divide(new BigDecimal(d), scale, rm));
131     }
132 
testDivideRounding()133     public void testDivideRounding() {
134         // checkDivide(expected, dividend, divisor, scale, roundingMode)
135         checkDivide("0", 1, Long.MIN_VALUE, 0, RoundingMode.DOWN);
136         checkDivide("-1", 1, Long.MIN_VALUE, 0, RoundingMode.UP);
137         checkDivide("-1", 1, Long.MIN_VALUE, 0, RoundingMode.FLOOR);
138         checkDivide("0", 1, Long.MIN_VALUE, 0, RoundingMode.CEILING);
139         checkDivide("0", 1, Long.MIN_VALUE, 0, RoundingMode.HALF_EVEN);
140         checkDivide("0", 1, Long.MIN_VALUE, 0, RoundingMode.HALF_UP);
141         checkDivide("0", 1, Long.MIN_VALUE, 0, RoundingMode.HALF_DOWN);
142 
143         checkDivide("1", Long.MAX_VALUE, Long.MAX_VALUE / 2 + 1, 0, RoundingMode.DOWN);
144         checkDivide("2", Long.MAX_VALUE, Long.MAX_VALUE / 2, 0, RoundingMode.DOWN);
145         checkDivide("0.50", Long.MAX_VALUE / 2, Long.MAX_VALUE, 2, RoundingMode.HALF_UP);
146         checkDivide("0.50", Long.MIN_VALUE / 2, Long.MIN_VALUE, 2, RoundingMode.HALF_UP);
147         checkDivide("0.5000", Long.MIN_VALUE / 2, Long.MIN_VALUE, 4, RoundingMode.HALF_UP);
148         // (-2^62 + 1) / (-2^63) = (2^62 - 1) / 2^63 = 0.5 - 2^-63
149         checkDivide("0", Long.MIN_VALUE / 2 + 1, Long.MIN_VALUE, 0, RoundingMode.HALF_UP);
150         checkDivide("1", Long.MIN_VALUE / 2, Long.MIN_VALUE, 0, RoundingMode.HALF_UP);
151         checkDivide("0", Long.MIN_VALUE / 2, Long.MIN_VALUE, 0, RoundingMode.HALF_DOWN);
152         // (-2^62 - 1) / (-2^63) = (2^62 + 1) / 2^63 = 0.5 + 2^-63
153         checkDivide("1", Long.MIN_VALUE / 2 - 1, Long.MIN_VALUE, 0, RoundingMode.HALF_DOWN);
154     }
155 
156     /**
157      * Test a bunch of pairings with even/odd dividend and divisor whose
158      * result is near +/- 0.5.
159      */
testDivideRounding_sign()160     public void testDivideRounding_sign() {
161         // checkDivide(expected, dividend, divisor, scale, roundingMode)
162         // positive dividend and divisor, even/odd values
163         checkDivide("0", 49, 100, 0, RoundingMode.HALF_UP);
164         checkDivide("1", 50, 100, 0, RoundingMode.HALF_UP);
165         checkDivide("1", 51, 101, 0, RoundingMode.HALF_UP);
166         checkDivide("0", 50, 101, 0, RoundingMode.HALF_UP);
167         checkDivide("0", Long.MAX_VALUE / 2, Long.MAX_VALUE, 0, RoundingMode.HALF_UP);
168 
169         // Same with negative dividend and divisor
170         checkDivide("0", -49, -100, 0, RoundingMode.HALF_UP);
171         checkDivide("1", -50, -100, 0, RoundingMode.HALF_UP);
172         checkDivide("1", -51, -101, 0, RoundingMode.HALF_UP);
173         checkDivide("0", -50, -101, 0, RoundingMode.HALF_UP);
174         checkDivide("0", -(Long.MAX_VALUE / 2), -Long.MAX_VALUE, 0, RoundingMode.HALF_UP);
175 
176         // Same with negative dividend
177         checkDivide("0", -49, 100, 0, RoundingMode.HALF_UP);
178         checkDivide("-1", -50, 100, 0, RoundingMode.HALF_UP);
179         checkDivide("-1", -51, 101, 0, RoundingMode.HALF_UP);
180         checkDivide("0", -50, 101, 0, RoundingMode.HALF_UP);
181         checkDivide("0", -(Long.MAX_VALUE / 2), Long.MAX_VALUE, 0, RoundingMode.HALF_UP);
182 
183         // Same with negative divisor
184         checkDivide("0", 49, -100, 0, RoundingMode.HALF_UP);
185         checkDivide("-1", 50, -100, 0, RoundingMode.HALF_UP);
186         checkDivide("-1", 51, -101, 0, RoundingMode.HALF_UP);
187         checkDivide("0", 50, -101, 0, RoundingMode.HALF_UP);
188         checkDivide("0", Long.MAX_VALUE / 2, -Long.MAX_VALUE, 0, RoundingMode.HALF_UP);
189     }
190 
testDivideByOne()191     public void testDivideByOne() {
192         long[] dividends = new long[] {
193                 Long.MIN_VALUE,
194                 Long.MIN_VALUE + 1,
195                 Long.MAX_VALUE,
196                 Long.MAX_VALUE - 1,
197                 0,
198                 -1,
199                 1,
200                 10, 43, 314159265358979323L, // arbitrary values
201         };
202         for (long dividend : dividends) {
203             String expected = Long.toString(dividend);
204             checkDivide(expected, dividend, 1, 0, RoundingMode.UNNECESSARY);
205         }
206     }
207 
testNegate()208     public void testNegate() {
209         checkNegate(valueOf(0), valueOf(0));
210         checkNegate(valueOf(1), valueOf(-1));
211         checkNegate(valueOf(43), valueOf(-43));
212         checkNegate(valueOf(Long.MAX_VALUE), valueOf(-Long.MAX_VALUE));
213         checkNegate(new BigDecimal("9223372036854775808"), valueOf(Long.MIN_VALUE));
214         // arbitrary large decimal
215         checkNegate(new BigDecimal("342343243546465623424321423112321.43243434343412321"),
216                 new BigDecimal("-342343243546465623424321423112321.43243434343412321"));
217     }
218 
checkNegate(BigDecimal a, BigDecimal b)219     private static void checkNegate(BigDecimal a, BigDecimal b) {
220         if (!a.toString().equals("0")) {
221             assertFalse(a.equals(b));
222         }
223         assertEquals(a.negate(), b);
224         assertEquals(a, b.negate());
225         assertEquals(a, a.negate().negate());
226     }
227 
testAddAndSubtract_near64BitOverflow()228     public void testAddAndSubtract_near64BitOverflow() throws Exception {
229         // Check that the test is set up correctly - these values should be MIN_VALUE and MAX_VALUE
230         assertEquals("-9223372036854775808", Long.toString(Long.MIN_VALUE));
231         assertEquals("9223372036854775807", Long.toString(Long.MAX_VALUE));
232 
233         // Exactly MIN_VALUE and MAX_VALUE
234         assertSum("-9223372036854775808", -(1L << 62L), -(1L << 62L));
235         assertSum("9223372036854775807", (1L << 62L) - 1L, 1L << 62L);
236 
237         // One beyond MIN_VALUE and MAX_VALUE
238         assertSum("-9223372036854775809", -(1L << 62L), -(1L << 62L) - 1);
239         assertSum("-9223372036854775809", Long.MIN_VALUE + 1, -2);
240         assertSum("9223372036854775808", 1L << 62L, 1L << 62L);
241         assertSum("9223372036854775808", Long.MAX_VALUE, 1);
242     }
243 
244     /**
245      * Assert that {@code (a + b), (b + a), (a - (-b)) and (b - (-a))} all have the same
246      * expected result in BigDecimal arithmetic.
247      */
assertSum(String expectedSumAsString, long a, long b)248     private static void assertSum(String expectedSumAsString, long a, long b) {
249         if (a == Long.MIN_VALUE || b == Long.MIN_VALUE) {
250             // - (Long.MIN_VALUE) can't be represented as a long, so don't allow it here.
251             throw new IllegalArgumentException("Long.MIN_VALUE not allowed");
252         }
253         BigDecimal bigA = valueOf(a);
254         BigDecimal bigB = valueOf(b);
255         BigDecimal bigMinusB = valueOf(-b);
256         BigDecimal bigMinusA = valueOf(-a);
257 
258         assertEquals("a + b", expectedSumAsString, bigA.add(bigB).toString());
259         assertEquals("b + a", expectedSumAsString, bigB.add(bigA).toString());
260         assertEquals("a - (-b)", expectedSumAsString, bigA.subtract(bigMinusB).toString());
261         assertEquals("b - (-a)", expectedSumAsString, bigB.subtract(bigMinusA).toString());
262     }
263 
264     /**
265      * Tests that Long.MIN_VALUE / -1 doesn't overflow back to Long.MIN_VALUE,
266      * like it would in long arithmetic.
267      */
268     // https://code.google.com/p/android/issues/detail?id=196555
testDivideAvoids64bitOverflow()269     public void testDivideAvoids64bitOverflow() throws Exception {
270         BigDecimal minLong = new BigDecimal("-9223372036854775808");
271         assertEquals("9223372036854775808/(-1)",
272                 new BigDecimal("9223372036854775808"),
273                 minLong.divide(new BigDecimal("-1"), /* scale = */ 0, RoundingMode.UNNECESSARY));
274 
275         assertEquals("922337203685477580.8/(-0.1)",
276                 new BigDecimal("9223372036854775808"),
277                 new BigDecimal("-922337203685477580.8")
278                         .divide(new BigDecimal("-0.1"), /* scale = */ 0, RoundingMode.UNNECESSARY));
279 
280         assertEquals("92233720368547758080/(-1E+1)",
281                 new BigDecimal("9223372036854775808"),
282                 new BigDecimal("-92233720368547758080")
283                         .divide(new BigDecimal("-1E+1"), /* scale = */ 0, RoundingMode.UNNECESSARY));
284 
285         assertEquals("9223372036854775808/(-10) with one decimal of precision",
286                 new BigDecimal("922337203685477580.8"),
287                 minLong.divide(new BigDecimal("-1E+1"), /* scale = */ 1, RoundingMode.UNNECESSARY));
288 
289         // cases that request adjustment of the result scale, i.e. (diffScale != 0)
290         // i.e. result scale != (dividend.scale - divisor.scale)
291         assertEquals("9223372036854775808/(-1) with one decimal of precision",//
292                 new BigDecimal("9223372036854775808.0"),
293                 minLong.divide(new BigDecimal("-1"), /* scale = */ 1, RoundingMode.UNNECESSARY));
294 
295         assertEquals("9223372036854775808/(-1.0)",//
296                 new BigDecimal("9223372036854775808"),
297                 minLong.divide(new BigDecimal("-1.0"), /* scale = */ 0, RoundingMode.UNNECESSARY));
298 
299         assertEquals("9223372036854775808/(-1.0) with one decimal of precision",//
300                 new BigDecimal("9223372036854775808.0"),
301                 minLong.divide(new BigDecimal("-1.0"), /* scale = */ 1, RoundingMode.UNNECESSARY));
302 
303         // another arbitrary calculation that results in Long.MAX_VALUE + 1
304         // via a different route
305         assertEquals("4611686018427387904/(-5E-1)",//
306                 new BigDecimal("9223372036854775808"),
307                 new BigDecimal("-4611686018427387904").divide(
308                         new BigDecimal("-5E-1"), /* scale = */ 0, RoundingMode.UNNECESSARY));
309     }
310 
311     /**
312      * Tests addition, subtraction, multiplication and division involving a range of
313      * even long values and 1/2 of that value.
314      */
testCommonOperations_halfOfEvenLongValue()315     public void testCommonOperations_halfOfEvenLongValue() {
316         checkCommonOperations(0);
317         checkCommonOperations(2);
318         checkCommonOperations(-2);
319         checkCommonOperations(Long.MIN_VALUE);
320         checkCommonOperations(1L << 62L);
321         checkCommonOperations(-(1L << 62L));
322         checkCommonOperations(1L << 62L + 1 << 30 + 1 << 10);
323         checkCommonOperations(Long.MAX_VALUE - 1);
324     }
325 
checkCommonOperations(long value)326     private static void checkCommonOperations(long value) {
327         if (value % 2 != 0) {
328             throw new IllegalArgumentException("Expected even value, got " + value);
329         }
330         BigDecimal bigHalfValue = valueOf(value / 2);
331         BigDecimal bigValue = valueOf(value);
332         BigDecimal two = valueOf(2);
333 
334         assertEquals(bigValue, bigHalfValue.multiply(two));
335         assertEquals(bigValue, bigHalfValue.add(bigHalfValue));
336         assertEquals(bigHalfValue, bigValue.subtract(bigHalfValue));
337         assertEquals(bigHalfValue, bigValue.divide(two, RoundingMode.UNNECESSARY));
338         if (value != 0) {
339             assertEquals(two, bigValue.divide(bigHalfValue, RoundingMode.UNNECESSARY));
340         }
341     }
342 
343     /**
344      * Tests that when long multiplication doesn't overflow, its result is consistent with
345      * BigDecimal multiplication.
346      */
testMultiply_consistentWithLong()347     public void testMultiply_consistentWithLong() {
348         checkMultiply_consistentWithLong(0, 0);
349         checkMultiply_consistentWithLong(0, 1);
350         checkMultiply_consistentWithLong(1, 1);
351         checkMultiply_consistentWithLong(2, 3);
352         checkMultiply_consistentWithLong(123, 456);
353         checkMultiply_consistentWithLong(9, 9);
354         checkMultiply_consistentWithLong(34545, 3423421);
355         checkMultiply_consistentWithLong(5465653, 342343234568L);
356         checkMultiply_consistentWithLong(Integer.MAX_VALUE, Integer.MAX_VALUE);
357         checkMultiply_consistentWithLong((1L << 40) + 454L, 34324);
358     }
359 
checkMultiply_consistentWithLong(long a, long b)360     private void checkMultiply_consistentWithLong(long a, long b) {
361         // Guard against the test using examples that overflow. This condition here is
362         // not meant to be exact, it'll reject some values that wouldn't overflow.
363         if (a != 0 && b != 0 && Math.abs(Long.MAX_VALUE / a) <= Math.abs(b)) {
364             throw new IllegalArgumentException("Multiplication might overflow: " + a + " * " + b);
365         }
366         long expectedResult = a * b;
367         // check the easy case with no decimals
368         assertEquals(Long.toString(expectedResult),
369                 valueOf(a).multiply(valueOf(b)).toString());
370         // number with 2 decimals * number with 3 decimals => number with 5 decimals
371         // E.g. 9E-2 * 2E-3 == 18E-5 == 0.00018
372         // valueOf(unscaledValue, scale) corresponds to {@code unscaledValue * 10<sup>-scale</sup>}
373         assertEquals(valueOf(expectedResult, 5), valueOf(a, 2).multiply(valueOf(b, 3)));
374     }
375 
testMultiply_near64BitOverflow_scaled()376     public void testMultiply_near64BitOverflow_scaled() {
377         // -((2^31) / 100) * (-2/10) == (2^64)/1000
378         assertEquals("9223372036854775.808",
379                 valueOf(-(1L << 62L), 2).multiply(valueOf(-2, 1)).toString());
380 
381         // -((2^31) / 100) * (2/10) == -(2^64)/1000
382         assertEquals("-9223372036854775.808",
383                 valueOf(-(1L << 62L), 2).multiply(valueOf(2, 1)).toString());
384 
385         // -((2^31) * 100) * (-2/10) == (2^64) * 10
386         assertEquals(new BigDecimal("9223372036854775808E1"),
387                 valueOf(-(1L << 62L), -2).multiply(valueOf(-2, 1)));
388     }
389 
390     /** Tests multiplications whose result is near 2^63 (= Long.MAX_VALUE + 1). */
testMultiply_near64BitOverflow_positive()391     public void testMultiply_near64BitOverflow_positive() {
392         // Results of exactly +2^63, which doesn't fit into a long even though -2^63 does
393         assertEquals("9223372036854775808", bigMultiply(Long.MIN_VALUE, -1).toString());
394         assertEquals("9223372036854775808", bigMultiply(Long.MIN_VALUE / 2, -2).toString());
395         assertEquals("9223372036854775808", bigMultiply(-(Long.MIN_VALUE / 2), 2).toString());
396         assertEquals("9223372036854775808", bigMultiply(1L << 31, 1L << 32).toString());
397         assertEquals("9223372036854775808", bigMultiply(-(1L << 31), -(1L << 32)).toString());
398 
399         // Results near but not exactly +2^63
400         assertEquals("9223372036854775806", bigMultiply(2147483647, 4294967298L).toString());
401         assertEquals("9223372036854775807", bigMultiply(Long.MAX_VALUE, 1).toString());
402         assertEquals("9223372036854775807", bigMultiply(42128471623L, 218934409L).toString());
403         assertEquals("9223372036854775809", bigMultiply(77158673929L, 119537721L).toString());
404         assertEquals("9223372036854775810", bigMultiply((1L << 62L) + 1, 2).toString());
405     }
406 
407     /** Tests multiplications whose result is near -2^63 (= Long.MIN_VALUE). */
testMultiply_near64BitOverflow_negative()408     public void testMultiply_near64BitOverflow_negative() {
409         assertEquals("-9223372036854775808", bigMultiply(Long.MIN_VALUE, 1).toString());
410         assertEquals("-9223372036854775808", bigMultiply(Long.MIN_VALUE / 2, 2).toString());
411         assertEquals("-9223372036854775808", bigMultiply(-(1L << 31), 1L << 32).toString());
412         assertEquals("-9223372036854775807", bigMultiply(-42128471623L, 218934409L).toString());
413         assertEquals("-9223372036854775810", bigMultiply(-(Long.MIN_VALUE / 2) + 1, -2).toString());
414     }
415 
bigMultiply(long a, long b)416     private static BigDecimal bigMultiply(long a, long b) {
417         BigDecimal bigA = valueOf(a);
418         BigDecimal bigB = valueOf(b);
419         BigDecimal result = bigA.multiply(bigB);
420         assertEquals("Multiplication should be commutative", result, bigB.multiply(bigA));
421         return result;
422     }
423 
424 }
425