1 /*
   2  * Copyright (c) 2012, 2019, 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 
  24 import java.math.BigInteger;
  25 
  26 /**
  27  * @test Test for Math.*Exact integer and long methods.
  28  * @bug 6708398
  29  * @summary Basic tests for Math exact arithmetic operations.
  30  *
  31  * @author Roger Riggs
  32  */
  33 public class ExactArithTests {
  34 
  35     /**
  36      * The count of test errors.
  37      */
  38     private static int errors = 0;
  39 
  40     /**
  41      * @param args the command line arguments
  42      */
  43     public static void main(String[] args) {
  44         testIntegerExact();
  45         testLongExact();
  46         testLongIntExact();
  47 
  48         if (errors > 0) {
  49             throw new RuntimeException(errors + " errors found in ExactArithTests.");
  50         }
  51     }
  52 
  53     static void fail(String message) {
  54         errors++;
  55         System.err.println(message);
  56     }
  57 
  58     /**
  59      * Test Math.addExact, multiplyExact, subtractExact, incrementExact,
  60      * decrementExact, negateExact methods with {@code int} arguments.
  61      */
  62     static void testIntegerExact() {
  63         testIntegerExact(0, 0);
  64         testIntegerExact(1, 1);
  65         testIntegerExact(1, -1);
  66         testIntegerExact(-1, 1);
  67         testIntegerExact(1000, 2000);
  68 
  69         testIntegerExact(Integer.MIN_VALUE, Integer.MIN_VALUE);
  70         testIntegerExact(Integer.MAX_VALUE, Integer.MAX_VALUE);
  71         testIntegerExact(Integer.MIN_VALUE, 1);
  72         testIntegerExact(Integer.MAX_VALUE, 1);
  73         testIntegerExact(Integer.MIN_VALUE, 2);
  74         testIntegerExact(Integer.MAX_VALUE, 2);
  75         testIntegerExact(Integer.MIN_VALUE, -1);
  76         testIntegerExact(Integer.MAX_VALUE, -1);
  77         testIntegerExact(Integer.MIN_VALUE, -2);
  78         testIntegerExact(Integer.MAX_VALUE, -2);
  79     }
  80 
  81     /**
  82      * Test exact arithmetic by comparing with the same operations using long
  83      * and checking that the result is the same as the integer truncation.
  84      * Errors are reported with {@link fail}.
  85      *
  86      * @param x first parameter
  87      * @param y second parameter
  88      */
  89     static void testIntegerExact(int x, int y) {
  90         try {
  91             // Test addExact
  92             int sum = Math.addExact(x, y);
  93             long sum2 = (long) x + (long) y;
  94             if ((int) sum2 != sum2) {
  95                 fail("FAIL: int Math.addExact(" + x + " + " + y + ") = " + sum + "; expected Arithmetic exception");
  96             } else if (sum != sum2) {
  97                 fail("FAIL: long Math.addExact(" + x + " + " + y + ") = " + sum + "; expected: " + sum2);
  98             }
  99         } catch (ArithmeticException ex) {
 100             long sum2 = (long) x + (long) y;
 101             if ((int) sum2 == sum2) {
 102                 fail("FAIL: int Math.addExact(" + x + " + " + y + ")" + "; Unexpected exception: " + ex);
 103             }
 104         }
 105 
 106         try {
 107             // Test subtractExact
 108             int diff = Math.subtractExact(x, y);
 109             long diff2 = (long) x - (long) y;
 110             if ((int) diff2 != diff2) {
 111                 fail("FAIL: int Math.subtractExact(" + x + " - " + y + ") = " + diff + "; expected: " + diff2);
 112             }
 113 
 114         } catch (ArithmeticException ex) {
 115             long diff2 = (long) x - (long) y;
 116             if ((int) diff2 == diff2) {
 117                 fail("FAIL: int Math.subtractExact(" + x + " - " + y + ")" + "; Unexpected exception: " + ex);
 118             }
 119         }
 120 
 121         try {
 122             // Test multiplyExact
 123             int product = Math.multiplyExact(x, y);
 124             long m2 = (long) x * (long) y;
 125             if ((int) m2 != m2) {
 126                 fail("FAIL: int Math.multiplyExact(" + x + " * " + y + ") = " + product + "; expected: " + m2);
 127             }
 128         } catch (ArithmeticException ex) {
 129             long m2 = (long) x * (long) y;
 130             if ((int) m2 == m2) {
 131                 fail("FAIL: int Math.multiplyExact(" + x + " * " + y + ")" + "; Unexpected exception: " + ex);
 132             }
 133         }
 134 
 135         try {
 136             // Test incrementExact
 137             int inc = Math.incrementExact(x);
 138             long inc2 = (long) x + 1L;
 139             if ((int) inc2 != inc2) {
 140                 fail("FAIL: int Math.incrementExact(" + x + ") = " + inc + "; expected Arithmetic exception");
 141             } else if (inc != inc2) {
 142                 fail("FAIL: long Math.incrementExact(" + x + ") = " + inc + "; expected: " + inc2);
 143             }
 144         } catch (ArithmeticException ex) {
 145             long inc2 = (long) x + 1L;
 146             if ((int) inc2 == inc2) {
 147                 fail("FAIL: int Math.incrementExact(" + x + ")" + "; Unexpected exception: " + ex);
 148             }
 149         }
 150 
 151         try {
 152             // Test decrementExact
 153             int dec = Math.decrementExact(x);
 154             long dec2 = (long) x - 1L;
 155             if ((int) dec2 != dec2) {
 156                 fail("FAIL: int Math.decrementExact(" + x + ") = " + dec + "; expected Arithmetic exception");
 157             } else if (dec != dec2) {
 158                 fail("FAIL: long Math.decrementExact(" + x + ") = " + dec + "; expected: " + dec2);
 159             }
 160         } catch (ArithmeticException ex) {
 161             long dec2 = (long) x - 1L;
 162             if ((int) dec2 == dec2) {
 163                 fail("FAIL: int Math.decrementExact(" + x + ")" + "; Unexpected exception: " + ex);
 164             }
 165         }
 166 
 167         try {
 168             // Test negateExact
 169             int neg = Math.negateExact(x);
 170             long neg2 = -((long)x) ;
 171             if ((int) neg2 != neg2) {
 172                 fail("FAIL: int Math.negateExact(" + x + ") = " + neg + "; expected Arithmetic exception");
 173             } else if (neg != neg2) {
 174                 fail("FAIL: long Math.negateExact(" + x + ") = " + neg + "; expected: " + neg2);
 175             }
 176         } catch (ArithmeticException ex) {
 177             long neg2 = (long) x - 1L;
 178             if ((int) neg2 == neg2) {
 179                 fail("FAIL: int Math.negateExact(" + x + ")" + "; Unexpected exception: " + ex);
 180             }
 181         }
 182     }
 183 
 184     /**
 185      * Test Math.addExact, multiplyExact, subtractExact, incrementExact,
 186      * decrementExact, negateExact, toIntExact methods with {@code long} arguments.
 187      */
 188     static void testLongExact() {
 189         testLongExactTwice(0, 0);
 190         testLongExactTwice(1, 1);
 191         testLongExactTwice(1, -1);
 192         testLongExactTwice(1000, 2000);
 193 
 194         testLongExactTwice(Long.MIN_VALUE, Long.MIN_VALUE);
 195         testLongExactTwice(Long.MAX_VALUE, Long.MAX_VALUE);
 196         testLongExactTwice(Long.MIN_VALUE, 1);
 197         testLongExactTwice(Long.MAX_VALUE, 1);
 198         testLongExactTwice(Long.MIN_VALUE, 2);
 199         testLongExactTwice(Long.MAX_VALUE, 2);
 200         testLongExactTwice(Long.MIN_VALUE, -1);
 201         testLongExactTwice(Long.MAX_VALUE, -1);
 202         testLongExactTwice(Long.MIN_VALUE, -2);
 203         testLongExactTwice(Long.MAX_VALUE, -2);
 204         testLongExactTwice(Long.MIN_VALUE/2, 2);
 205         testLongExactTwice(Long.MAX_VALUE, 2);
 206         testLongExactTwice(Integer.MAX_VALUE, Integer.MAX_VALUE);
 207         testLongExactTwice(Integer.MAX_VALUE, -Integer.MAX_VALUE);
 208         testLongExactTwice(Integer.MAX_VALUE+1, Integer.MAX_VALUE+1);
 209         testLongExactTwice(Integer.MAX_VALUE+1, -Integer.MAX_VALUE+1);
 210         testLongExactTwice(Integer.MIN_VALUE-1, Integer.MIN_VALUE-1);
 211         testLongExactTwice(Integer.MIN_VALUE-1, -Integer.MIN_VALUE-1);
 212         testLongExactTwice(Integer.MIN_VALUE/2, 2);
 213     }
 214 
 215     /**
 216      * Test each of the exact operations with the arguments and
 217      * with the arguments reversed.
 218      * @param x
 219      * @param y
 220      */
 221     static void testLongExactTwice(long x, long y) {
 222         testLongExact(x, y);
 223         testLongExact(y, x);
 224     }
 225 
 226 
 227     /**
 228      * Test long exact arithmetic by comparing with the same operations using BigInteger
 229      * and checking that the result is the same as the long truncation.
 230      * Errors are reported with {@link fail}.
 231      *
 232      * @param x first parameter
 233      * @param y second parameter
 234      */
 235     static void testLongExact(long x, long y) {
 236         BigInteger resultBig = null;
 237         final BigInteger xBig = BigInteger.valueOf(x);
 238         final BigInteger yBig = BigInteger.valueOf(y);
 239         try {
 240             // Test addExact
 241             resultBig = xBig.add(yBig);
 242             long sum = Math.addExact(x, y);
 243             checkResult("long Math.addExact", x, y, sum, resultBig);
 244         } catch (ArithmeticException ex) {
 245             if (inLongRange(resultBig)) {
 246                 fail("FAIL: long Math.addExact(" + x + " + " + y + "); Unexpected exception: " + ex);
 247             }
 248         }
 249 
 250         try {
 251             // Test subtractExact
 252             resultBig = xBig.subtract(yBig);
 253             long diff = Math.subtractExact(x, y);
 254             checkResult("long Math.subtractExact", x, y, diff, resultBig);
 255         } catch (ArithmeticException ex) {
 256             if (inLongRange(resultBig)) {
 257                 fail("FAIL: long Math.subtractExact(" + x + " - " + y + ")" + "; Unexpected exception: " + ex);
 258             }
 259         }
 260 
 261         try {
 262             // Test multiplyExact
 263             resultBig = xBig.multiply(yBig);
 264             long product = Math.multiplyExact(x, y);
 265             checkResult("long Math.multiplyExact", x, y, product, resultBig);
 266         } catch (ArithmeticException ex) {
 267             if (inLongRange(resultBig)) {
 268                 fail("FAIL: long Math.multiplyExact(" + x + " * " + y + ")" + "; Unexpected exception: " + ex);
 269             }
 270         }
 271 
 272         try {
 273             // Test incrementExact
 274             resultBig = xBig.add(BigInteger.ONE);
 275             long inc = Math.incrementExact(x);
 276             checkResult("long Math.incrementExact", x, 1L, inc, resultBig);
 277         } catch (ArithmeticException ex) {
 278             if (inLongRange(resultBig)) {
 279                 fail("FAIL: long Math.incrementExact(" + x + "); Unexpected exception: " + ex);
 280             }
 281         }
 282 
 283         try {
 284             // Test decrementExact
 285             resultBig = xBig.subtract(BigInteger.ONE);
 286             long dec = Math.decrementExact(x);
 287             checkResult("long Math.decrementExact", x, 1L, dec, resultBig);
 288         } catch (ArithmeticException ex) {
 289             if (inLongRange(resultBig)) {
 290                 fail("FAIL: long Math.decrementExact(" + x + "); Unexpected exception: " + ex);
 291             }
 292         }
 293 
 294         try {
 295             // Test negateExact
 296             resultBig = xBig.negate();
 297             long dec = Math.negateExact(x);
 298             checkResult("long Math.negateExact", x, 0L, dec, resultBig);
 299         } catch (ArithmeticException ex) {
 300             if (inLongRange(resultBig)) {
 301                 fail("FAIL: long Math.negateExact(" + x + "); Unexpected exception: " + ex);
 302             }
 303         }
 304 
 305         try {
 306             // Test toIntExact
 307             int value = Math.toIntExact(x);
 308             if ((long)value != x) {
 309                 fail("FAIL: " + "long Math.toIntExact" + "(" + x + ") = " + value + "; expected an arithmetic exception: ");
 310             }
 311         } catch (ArithmeticException ex) {
 312             if (resultBig.bitLength() <= 32) {
 313                 fail("FAIL: long Math.toIntExact(" + x + ")" + "; Unexpected exception: " + ex);
 314             }
 315         }
 316     }
 317 
 318     /**
 319      * Compare the expected and actual results.
 320      * @param message message for the error
 321      * @param x first argument
 322      * @param y second argument
 323      * @param result actual result value
 324      * @param expected expected result value
 325      */
 326     static void checkResult(String message, long x, long y, long result, BigInteger expected) {
 327         BigInteger resultBig = BigInteger.valueOf(result);
 328         if (!inLongRange(expected)) {
 329             fail("FAIL: " + message + "(" + x + ", " + y + ") = " + result + "; expected an arithmetic exception: ");
 330         } else if (!resultBig.equals(expected)) {
 331             fail("FAIL: " + message + "(" + x + ", " + y + ") = " + result + "; expected " + expected);
 332         }
 333     }
 334 
 335     /**
 336      * Check if the value fits in 64 bits (a long).
 337      * @param value
 338      * @return true if the value fits in 64 bits (including the sign).
 339      */
 340     static boolean inLongRange(BigInteger value) {
 341         return value.bitLength() <= 63;
 342     }
 343 
 344     /**
 345      * Test Math.multiplyExact method with {@code long} and {@code int}
 346      * arguments.
 347      */
 348     static void testLongIntExact() {
 349         testLongIntExact(0, 0);
 350         testLongIntExact(1, 1);
 351         testLongIntExact(1, -1);
 352         testLongIntExact(1000, 2000);
 353 
 354         testLongIntExact(Long.MIN_VALUE, Integer.MIN_VALUE);
 355         testLongIntExact(Long.MAX_VALUE, Integer.MAX_VALUE);
 356         testLongIntExact(Long.MIN_VALUE, 1);
 357         testLongIntExact(Long.MAX_VALUE, 1);
 358         testLongIntExact(Long.MIN_VALUE, 2);
 359         testLongIntExact(Long.MAX_VALUE, 2);
 360         testLongIntExact(Long.MIN_VALUE, -1);
 361         testLongIntExact(Long.MAX_VALUE, -1);
 362         testLongIntExact(Long.MIN_VALUE, -2);
 363         testLongIntExact(Long.MAX_VALUE, -2);
 364         testLongIntExact(Long.MIN_VALUE/2, 2);
 365         testLongIntExact(Long.MAX_VALUE, 2);
 366         testLongIntExact(Integer.MAX_VALUE, Integer.MAX_VALUE);
 367         testLongIntExact(Integer.MAX_VALUE, -Integer.MAX_VALUE);
 368         testLongIntExact((long)Integer.MAX_VALUE+1L, Integer.MAX_VALUE);
 369         testLongIntExact((long)Integer.MAX_VALUE+1L, -Integer.MAX_VALUE+1);
 370         testLongIntExact((long)Integer.MIN_VALUE-1L, Integer.MIN_VALUE);
 371         testLongIntExact((long)Integer.MIN_VALUE-1, Integer.MAX_VALUE);
 372         testLongIntExact(Integer.MIN_VALUE/2, 2);
 373     }
 374 
 375     /**
 376      * Test long-int exact arithmetic by comparing with the same operations using BigInteger
 377      * and checking that the result is the same as the long truncation.
 378      * Errors are reported with {@link fail}.
 379      *
 380      * @param x first parameter
 381      * @param y second parameter
 382      */
 383     static void testLongIntExact(long x, int y) {
 384         BigInteger resultBig = null;
 385         final BigInteger xBig = BigInteger.valueOf(x);
 386         final BigInteger yBig = BigInteger.valueOf(y);
 387 
 388         try {
 389             // Test multiplyExact
 390             resultBig = xBig.multiply(yBig);
 391             long product = Math.multiplyExact(x, y);
 392             checkResult("long Math.multiplyExact", x, y, product, resultBig);
 393         } catch (ArithmeticException ex) {
 394             if (inLongRange(resultBig)) {
 395                 fail("FAIL: long Math.multiplyExact(" + x + " * " + y + ")" + "; Unexpected exception: " + ex);
 396             }
 397         }
 398     }
 399 }