1 /* 2 * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package test.java.lang.Math; 24 25 import java.math.BigInteger; 26 27 import org.testng.annotations.Test; 28 29 import static org.testng.Assert.fail; 30 31 // Android-changed: Added test annotations, remove main() method. 32 33 /** 34 * @test Test for Math.*Exact integer and long methods. 35 * @bug 6708398 8075806 8271225 8271602 36 * @summary Basic tests for Math exact arithmetic operations. 37 * 38 * @author Roger Riggs 39 */ 40 public class ExactArithTests { 41 /** 42 * The count of test errors. 43 */ 44 private static int errors = 0; 45 46 /** 47 * @param args the command line arguments 48 */ 49 // Android-changed: Added test annotations, remove main() method. 50 /* 51 public static void main(String[] args) { 52 testIntegerExact(); 53 testLongExact(); 54 testLongIntExact(); 55 56 if (errors > 0) { 57 throw new RuntimeException(errors + " errors found in ExactArithTests."); 58 } 59 } 60 61 static void fail(String message) { 62 errors++; 63 System.err.println(message); 64 } 65 */ 66 67 /** 68 * Test Math.addExact, multiplyExact, divideExact, subtractExact, 69 * floorDivExact, ceilDivExact, incrementExact, decrementExact, negateExact 70 * methods with {@code int} arguments. 71 */ 72 @Test testIntegerExact()73 public void testIntegerExact() { 74 testIntegerExact(0, 0); 75 testIntegerExact(1, 1); 76 testIntegerExact(1, -1); 77 testIntegerExact(-1, 1); 78 testIntegerExact(1000, 2000); 79 80 testIntegerExact(Integer.MIN_VALUE, Integer.MIN_VALUE); 81 testIntegerExact(Integer.MAX_VALUE, Integer.MAX_VALUE); 82 testIntegerExact(Integer.MIN_VALUE, 1); 83 testIntegerExact(Integer.MAX_VALUE, 1); 84 testIntegerExact(Integer.MIN_VALUE, 2); 85 testIntegerExact(Integer.MAX_VALUE, 2); 86 testIntegerExact(Integer.MIN_VALUE, -1); 87 testIntegerExact(Integer.MAX_VALUE, -1); 88 testIntegerExact(Integer.MIN_VALUE, -2); 89 testIntegerExact(Integer.MAX_VALUE, -2); 90 } 91 92 /** 93 * Test exact arithmetic by comparing with the same operations using long 94 * and checking that the result is the same as the integer truncation. 95 * 96 * @param x first parameter 97 * @param y second parameter 98 */ testIntegerExact(int x, int y)99 static void testIntegerExact(int x, int y) { 100 try { 101 // Test addExact 102 int sum = Math.addExact(x, y); 103 long sum2 = (long) x + (long) y; 104 if ((int) sum2 != sum2) { 105 fail("FAIL: int Math.addExact(" + x + " + " + y + ") = " + sum + "; expected Arithmetic exception"); 106 } else if (sum != sum2) { 107 fail("FAIL: long Math.addExact(" + x + " + " + y + ") = " + sum + "; expected: " + sum2); 108 } 109 } catch (ArithmeticException ex) { 110 long sum2 = (long) x + (long) y; 111 if ((int) sum2 == sum2) { 112 fail("FAIL: int Math.addExact(" + x + " + " + y + ")" + "; Unexpected exception: " + ex); 113 } 114 } 115 116 try { 117 // Test subtractExact 118 int diff = Math.subtractExact(x, y); 119 long diff2 = (long) x - (long) y; 120 if ((int) diff2 != diff2) { 121 fail("FAIL: int Math.subtractExact(" + x + " - " + y + ") = " + diff + "; expected: " + diff2); 122 } 123 124 } catch (ArithmeticException ex) { 125 long diff2 = (long) x - (long) y; 126 if ((int) diff2 == diff2) { 127 fail("FAIL: int Math.subtractExact(" + x + " - " + y + ")" + "; Unexpected exception: " + ex); 128 } 129 } 130 131 try { 132 // Test multiplyExact 133 int product = Math.multiplyExact(x, y); 134 long m2 = (long) x * (long) y; 135 if ((int) m2 != m2) { 136 fail("FAIL: int Math.multiplyExact(" + x + " * " + y + ") = " + product + "; expected: " + m2); 137 } 138 } catch (ArithmeticException ex) { 139 long m2 = (long) x * (long) y; 140 if ((int) m2 == m2) { 141 fail("FAIL: int Math.multiplyExact(" + x + " * " + y + ")" + "; Unexpected exception: " + ex); 142 } 143 } 144 145 boolean exceptionExpected = false; 146 try { 147 // Test divideExact 148 BigInteger q = null; 149 try { 150 q = BigInteger.valueOf(x).divide(BigInteger.valueOf(y)); 151 } catch (ArithmeticException e) { 152 exceptionExpected = true; 153 } 154 int quotient = 0; 155 if (q != null) { 156 try { 157 quotient = q.intValueExact(); 158 } catch (ArithmeticException e) { 159 exceptionExpected = true; 160 } 161 } 162 int z = Math.divideExact(x, y); 163 if (exceptionExpected) { 164 fail("FAIL: int Math.divideExact(" + x + " / " + y + ")" + 165 "; expected ArithmeticException not thrown"); 166 } 167 if (z != quotient) { 168 fail("FAIL: int Math.divideExact(" + x + " / " + y + ") = " + 169 z + "; expected: " + quotient); 170 } 171 // Android-added: Test functionally-equivalent StrictMath version. 172 z = StrictMath.divideExact(x, y); 173 if (z != quotient) { 174 fail("FAIL: int StrictMath.divideExact(" + x + " / " + y + ") = " + 175 z + "; expected: " + q); 176 } 177 } catch (ArithmeticException ex) { 178 if (!exceptionExpected) { 179 fail("FAIL: int Math.divideExact(" + x + " / " + y + ")" + 180 "; Unexpected exception: " + ex); 181 } 182 } 183 184 exceptionExpected = false; 185 try { 186 // Test floorDivExact 187 int q = 0; 188 try { 189 q = Math.floorDiv(x, y); 190 } catch (ArithmeticException e) { 191 exceptionExpected = true; 192 } 193 if (!exceptionExpected && x == Integer.MIN_VALUE && y == -1) { 194 exceptionExpected = true; 195 } 196 int z = Math.floorDivExact(x, y); 197 if (exceptionExpected) { 198 fail("FAIL: int Math.floorDivExact(" + x + " / " + y + ")" + 199 "; expected ArithmeticException not thrown"); 200 } 201 if (z != q) { 202 fail("FAIL: int Math.floorDivExact(" + x + " / " + y + ") = " + 203 z + "; expected: " + q); 204 } 205 // Android-added: Test functionally-equivalent StrictMath version. 206 z = StrictMath.floorDivExact(x, y); 207 if (z != q) { 208 fail("FAIL: int StrictMath.floorDivExact(" + x + " / " + y + ") = " + 209 z + "; expected: " + q); 210 } 211 } catch (ArithmeticException ex) { 212 if (!exceptionExpected) { 213 fail("FAIL: int Math.floorDivExact(" + x + " / " + y + ")" + 214 "; Unexpected exception: " + ex); 215 } 216 } 217 218 exceptionExpected = false; 219 try { 220 // Test ceilDivExact 221 int q = 0; 222 try { 223 q = Math.ceilDiv(x, y); 224 } catch (ArithmeticException e) { 225 exceptionExpected = true; 226 } 227 if (!exceptionExpected && x == Integer.MIN_VALUE && y == -1) { 228 exceptionExpected = true; 229 } 230 int z = Math.ceilDivExact(x, y); 231 if (exceptionExpected) { 232 fail("FAIL: int Math.ceilDivExact(" + x + " / " + y + ")" + 233 "; expected ArithmeticException not thrown"); 234 } 235 if (z != q) { 236 fail("FAIL: int Math.ceilDivExact(" + x + " / " + y + ") = " + 237 z + "; expected: " + q); 238 } 239 // Android-added: Test functionally-equivalent StrictMath version. 240 if (z != StrictMath.ceilDivExact(x, y)) { 241 fail("FAIL: int StrictMath.ceilDivExact(" + x + " / " + y + ") = " + 242 z + "; expected: " + q); 243 } 244 } catch (ArithmeticException ex) { 245 if (!exceptionExpected) { 246 fail("FAIL: int Math.ceilDivExact(" + x + " / " + y + ")" + 247 "; Unexpected exception: " + ex); 248 } 249 } 250 251 try { 252 // Test incrementExact 253 int inc = Math.incrementExact(x); 254 long inc2 = (long) x + 1L; 255 if ((int) inc2 != inc2) { 256 fail("FAIL: int Math.incrementExact(" + x + ") = " + inc + "; expected Arithmetic exception"); 257 } else if (inc != inc2) { 258 fail("FAIL: long Math.incrementExact(" + x + ") = " + inc + "; expected: " + inc2); 259 } 260 } catch (ArithmeticException ex) { 261 long inc2 = (long) x + 1L; 262 if ((int) inc2 == inc2) { 263 fail("FAIL: int Math.incrementExact(" + x + ")" + "; Unexpected exception: " + ex); 264 } 265 } 266 267 try { 268 // Test decrementExact 269 int dec = Math.decrementExact(x); 270 long dec2 = (long) x - 1L; 271 if ((int) dec2 != dec2) { 272 fail("FAIL: int Math.decrementExact(" + x + ") = " + dec + "; expected Arithmetic exception"); 273 } else if (dec != dec2) { 274 fail("FAIL: long Math.decrementExact(" + x + ") = " + dec + "; expected: " + dec2); 275 } 276 } catch (ArithmeticException ex) { 277 long dec2 = (long) x - 1L; 278 if ((int) dec2 == dec2) { 279 fail("FAIL: int Math.decrementExact(" + x + ")" + "; Unexpected exception: " + ex); 280 } 281 } 282 283 try { 284 // Test negateExact 285 int neg = Math.negateExact(x); 286 long neg2 = -((long)x); 287 if ((int) neg2 != neg2) { 288 fail("FAIL: int Math.negateExact(" + x + ") = " + neg + "; expected Arithmetic exception"); 289 } else if (neg != neg2) { 290 fail("FAIL: long Math.negateExact(" + x + ") = " + neg + "; expected: " + neg2); 291 } 292 } catch (ArithmeticException ex) { 293 long neg2 = -((long)x); 294 if ((int) neg2 == neg2) { 295 fail("FAIL: int Math.negateExact(" + x + ")" + "; Unexpected exception: " + ex); 296 } 297 } 298 } 299 300 /** 301 * Test Math.addExact, multiplyExact, divideExact, subtractExact, 302 * floorDivExact, ceilDivExact, incrementExact, decrementExact, negateExact, toIntExact 303 * methods with {@code long} arguments. 304 */ 305 @Test testLongExact()306 public void testLongExact() { 307 testLongExactTwice(0, 0); 308 testLongExactTwice(1, 1); 309 testLongExactTwice(1, -1); 310 testLongExactTwice(1000, 2000); 311 312 testLongExactTwice(Long.MIN_VALUE, Long.MIN_VALUE); 313 testLongExactTwice(Long.MAX_VALUE, Long.MAX_VALUE); 314 testLongExactTwice(Long.MIN_VALUE, 1); 315 testLongExactTwice(Long.MAX_VALUE, 1); 316 testLongExactTwice(Long.MIN_VALUE, 2); 317 testLongExactTwice(Long.MAX_VALUE, 2); 318 testLongExactTwice(Long.MIN_VALUE, -1); 319 testLongExactTwice(Long.MAX_VALUE, -1); 320 testLongExactTwice(Long.MIN_VALUE, -2); 321 testLongExactTwice(Long.MAX_VALUE, -2); 322 testLongExactTwice(Long.MIN_VALUE / 2, 2); 323 testLongExactTwice(Long.MAX_VALUE, 2); 324 testLongExactTwice(Integer.MAX_VALUE, Integer.MAX_VALUE); 325 testLongExactTwice(Integer.MAX_VALUE, -Integer.MAX_VALUE); 326 testLongExactTwice(Integer.MAX_VALUE + 1, Integer.MAX_VALUE + 1); 327 testLongExactTwice(Integer.MAX_VALUE + 1, -Integer.MAX_VALUE + 1); 328 testLongExactTwice(Integer.MIN_VALUE - 1, Integer.MIN_VALUE - 1); 329 testLongExactTwice(Integer.MIN_VALUE - 1, -Integer.MIN_VALUE - 1); 330 testLongExactTwice(Integer.MIN_VALUE / 2, 2); 331 332 } 333 334 /** 335 * Test each of the exact operations with the arguments and 336 * with the arguments reversed. 337 * @param x 338 * @param y 339 */ testLongExactTwice(long x, long y)340 static void testLongExactTwice(long x, long y) { 341 testLongExact(x, y); 342 testLongExact(y, x); 343 } 344 345 346 /** 347 * Test long exact arithmetic by comparing with the same operations using BigInteger 348 * and checking that the result is the same as the long truncation. 349 * 350 * @param x first parameter 351 * @param y second parameter 352 */ testLongExact(long x, long y)353 static void testLongExact(long x, long y) { 354 BigInteger resultBig = null; 355 final BigInteger xBig = BigInteger.valueOf(x); 356 final BigInteger yBig = BigInteger.valueOf(y); 357 try { 358 // Test addExact 359 resultBig = xBig.add(yBig); 360 long sum = Math.addExact(x, y); 361 checkResult("long Math.addExact", x, y, sum, resultBig); 362 } catch (ArithmeticException ex) { 363 if (inLongRange(resultBig)) { 364 fail("FAIL: long Math.addExact(" + x + " + " + y + "); Unexpected exception: " + ex); 365 } 366 } 367 368 try { 369 // Test subtractExact 370 resultBig = xBig.subtract(yBig); 371 long diff = Math.subtractExact(x, y); 372 checkResult("long Math.subtractExact", x, y, diff, resultBig); 373 } catch (ArithmeticException ex) { 374 if (inLongRange(resultBig)) { 375 fail("FAIL: long Math.subtractExact(" + x + " - " + y + ")" + "; Unexpected exception: " + ex); 376 } 377 } 378 379 try { 380 // Test multiplyExact 381 resultBig = xBig.multiply(yBig); 382 long product = Math.multiplyExact(x, y); 383 checkResult("long Math.multiplyExact", x, y, product, resultBig); 384 } catch (ArithmeticException ex) { 385 if (inLongRange(resultBig)) { 386 fail("FAIL: long Math.multiplyExact(" + x + " * " + y + ")" + "; Unexpected exception: " + ex); 387 } 388 } 389 390 try { 391 // Test divideExact 392 resultBig = null; 393 try { 394 resultBig = xBig.divide(yBig); 395 } catch (ArithmeticException ex) { 396 } 397 long quotient = Math.divideExact(x, y); 398 if (resultBig == null) { 399 fail("FAIL: long Math.divideExact(" + x + " / " + y + ")" + 400 "; expected ArithmeticException not thrown"); 401 } 402 checkResult("long Math.divideExact", x, y, quotient, resultBig); 403 // Android-added: Test functionally-equivalent StrictMath version. 404 long quotient2 = StrictMath.divideExact(x, y); 405 if (quotient2 != quotient) { 406 fail("FAIL: long StrictMath.divideExact(" + x + " / " + y + ")" + 407 "; expected " + quotient + " but got " + quotient2); 408 } 409 checkResult("long StrictMath.divideExact", x, y, quotient2, resultBig); 410 } catch (ArithmeticException ex) { 411 if (resultBig != null && inLongRange(resultBig)) { 412 fail("FAIL: long Math.divideExact(" + x + " / " + y + ")" + 413 "; Unexpected exception: " + ex); 414 } 415 } 416 417 boolean exceptionExpected = false; 418 try { 419 // Test floorDivExact 420 long q = 0; 421 try { 422 q = Math.floorDiv(x, y); 423 } catch (ArithmeticException e) { 424 exceptionExpected = true; 425 } 426 if (!exceptionExpected && x == Long.MIN_VALUE && y == -1) { 427 exceptionExpected = true; 428 } 429 long z = Math.floorDivExact(x, y); 430 if (exceptionExpected) { 431 fail("FAIL: long Math.floorDivExact(" + x + " / " + y + ")" + 432 "; expected ArithmeticException not thrown"); 433 } 434 if (z != q) { 435 fail("FAIL: long Math.floorDivExact(" + x + " / " + y + ") = " + 436 z + "; expected: " + q); 437 } 438 // Android-added: Test functionally-equivalent StrictMath version. 439 z = StrictMath.floorDivExact(x, y); 440 if (z != q) { 441 fail("FAIL: long StrictMath.floorDivExact(" + x + " / " + y + ") = " + 442 z + "; expected: " + q); 443 } 444 } catch (ArithmeticException ex) { 445 if (!exceptionExpected) { 446 fail("FAIL: long Math.floorDivExact(" + x + " / " + y + ")" + 447 "; Unexpected exception: " + ex); 448 } 449 } 450 451 exceptionExpected = false; 452 try { 453 // Test ceilDivExact 454 long q = 0; 455 try { 456 q = Math.ceilDiv(x, y); 457 } catch (ArithmeticException e) { 458 exceptionExpected = true; 459 } 460 if (!exceptionExpected && x == Long.MIN_VALUE && y == -1) { 461 exceptionExpected = true; 462 } 463 long z = Math.ceilDivExact(x, y); 464 if (exceptionExpected) { 465 fail("FAIL: long Math.ceilDivExact(" + x + " / " + y + ")" + 466 "; expected ArithmeticException not thrown"); 467 } 468 if (z != q) { 469 fail("FAIL: long Math.ceilDivExact(" + x + " / " + y + ") = " + 470 z + "; expected: " + q); 471 } 472 // Android-added: Test functionally-equivalent StrictMath version. 473 z = StrictMath.ceilDivExact(x, y); 474 if (z != q) { 475 fail("FAIL: long StrictMath.ceilDivExact(" + x + " / " + y + ") = " + 476 z + "; expected: " + q); 477 } 478 } catch (ArithmeticException ex) { 479 if (!exceptionExpected) { 480 fail("FAIL: long Math.ceilDivExact(" + x + " / " + y + ")" + 481 "; Unexpected exception: " + ex); 482 } 483 } 484 485 try { 486 // Test incrementExact 487 resultBig = xBig.add(BigInteger.ONE); 488 long inc = Math.incrementExact(x); 489 checkResult("long Math.incrementExact", x, 1L, inc, resultBig); 490 } catch (ArithmeticException ex) { 491 if (inLongRange(resultBig)) { 492 fail("FAIL: long Math.incrementExact(" + x + "); Unexpected exception: " + ex); 493 } 494 } 495 496 try { 497 // Test decrementExact 498 resultBig = xBig.subtract(BigInteger.ONE); 499 long dec = Math.decrementExact(x); 500 checkResult("long Math.decrementExact", x, 1L, dec, resultBig); 501 } catch (ArithmeticException ex) { 502 if (inLongRange(resultBig)) { 503 fail("FAIL: long Math.decrementExact(" + x + "); Unexpected exception: " + ex); 504 } 505 } 506 507 try { 508 // Test negateExact 509 resultBig = xBig.negate(); 510 long dec = Math.negateExact(x); 511 checkResult("long Math.negateExact", x, 0L, dec, resultBig); 512 } catch (ArithmeticException ex) { 513 if (inLongRange(resultBig)) { 514 fail("FAIL: long Math.negateExact(" + x + "); Unexpected exception: " + ex); 515 } 516 } 517 518 try { 519 // Test toIntExact 520 int value = Math.toIntExact(x); 521 if ((long)value != x) { 522 fail("FAIL: " + "long Math.toIntExact" + "(" + x + ") = " + value + "; expected an arithmetic exception: "); 523 } 524 } catch (ArithmeticException ex) { 525 if (resultBig.bitLength() <= 32) { 526 fail("FAIL: long Math.toIntExact(" + x + ")" + "; Unexpected exception: " + ex); 527 } 528 } 529 } 530 531 /** 532 * Compare the expected and actual results. 533 * @param message message for the error 534 * @param x first argument 535 * @param y second argument 536 * @param result actual result value 537 * @param expected expected result value 538 */ checkResult(String message, long x, long y, long result, BigInteger expected)539 static void checkResult(String message, long x, long y, long result, BigInteger expected) { 540 BigInteger resultBig = BigInteger.valueOf(result); 541 if (!inLongRange(expected)) { 542 fail("FAIL: " + message + "(" + x + ", " + y + ") = " + result + "; expected an arithmetic exception: "); 543 } else if (!resultBig.equals(expected)) { 544 fail("FAIL: " + message + "(" + x + ", " + y + ") = " + result + "; expected " + expected); 545 } 546 } 547 548 /** 549 * Check if the value fits in 64 bits (a long). 550 * @param value 551 * @return true if the value fits in 64 bits (including the sign). 552 */ inLongRange(BigInteger value)553 static boolean inLongRange(BigInteger value) { 554 return value.bitLength() <= 63; 555 } 556 557 /** 558 * Test Math.multiplyExact method with {@code long} and {@code int} 559 * arguments. 560 */ 561 @Test testLongIntExact()562 public void testLongIntExact() { 563 testLongIntExact(0, 0); 564 testLongIntExact(1, 1); 565 testLongIntExact(1, -1); 566 testLongIntExact(1000, 2000); 567 568 testLongIntExact(Long.MIN_VALUE, Integer.MIN_VALUE); 569 testLongIntExact(Long.MAX_VALUE, Integer.MAX_VALUE); 570 testLongIntExact(Long.MIN_VALUE, 1); 571 testLongIntExact(Long.MAX_VALUE, 1); 572 testLongIntExact(Long.MIN_VALUE, 2); 573 testLongIntExact(Long.MAX_VALUE, 2); 574 testLongIntExact(Long.MIN_VALUE, -1); 575 testLongIntExact(Long.MAX_VALUE, -1); 576 testLongIntExact(Long.MIN_VALUE, -2); 577 testLongIntExact(Long.MAX_VALUE, -2); 578 testLongIntExact(Long.MIN_VALUE / 2, 2); 579 testLongIntExact(Long.MAX_VALUE, 2); 580 testLongIntExact(Integer.MAX_VALUE, Integer.MAX_VALUE); 581 testLongIntExact(Integer.MAX_VALUE, -Integer.MAX_VALUE); 582 testLongIntExact((long) Integer.MAX_VALUE + 1L, Integer.MAX_VALUE); 583 testLongIntExact((long) Integer.MAX_VALUE + 1L, -Integer.MAX_VALUE + 1); 584 testLongIntExact((long) Integer.MIN_VALUE - 1L, Integer.MIN_VALUE); 585 testLongIntExact((long) Integer.MIN_VALUE - 1, Integer.MAX_VALUE); 586 testLongIntExact(Integer.MIN_VALUE / 2, 2); 587 } 588 589 /** 590 * Test long-int exact arithmetic by comparing with the same operations using BigInteger 591 * and checking that the result is the same as the long truncation. 592 * 593 * @param x first parameter 594 * @param y second parameter 595 */ testLongIntExact(long x, int y)596 static void testLongIntExact(long x, int y) { 597 BigInteger resultBig = null; 598 final BigInteger xBig = BigInteger.valueOf(x); 599 final BigInteger yBig = BigInteger.valueOf(y); 600 601 try { 602 // Test multiplyExact 603 resultBig = xBig.multiply(yBig); 604 long product = Math.multiplyExact(x, y); 605 checkResult("long Math.multiplyExact", x, y, product, resultBig); 606 } catch (ArithmeticException ex) { 607 if (inLongRange(resultBig)) { 608 fail("FAIL: long Math.multiplyExact(" + x + " * " + y + ")" + "; Unexpected exception: " + ex); 609 } 610 } 611 } 612 } 613