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