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