Home | History | Annotate | Download | only in math
      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 
     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 
     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 
     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
     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 
     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
    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
    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 
    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 
    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      */
    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 
    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 
    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 
    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 
    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      */
    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
    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      */
    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 
    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      */
    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 
    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 
    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). */
    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). */
    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 
    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