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 StrictMath.*Exact integer and long methods.
  28  * @bug 6708398
  29  * @summary Basic tests for StrictMath 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 
  47         if (errors > 0) {
  48             throw new RuntimeException(errors + " errors found in ExactArithTests.");
  49         }
  50     }
  51 
  52     static void fail(String message) {
  53         errors++;
  54         System.err.println(message);
  55     }
  56 
  57     /**
  58      * Test StrictMath.addExact, multiplyExact, subtractExact, incrementExact,
  59      * decrementExact, negateExact methods with {@code int} arguments.
  60      */
  61     static void testIntegerExact() {
  62         testIntegerExact(0, 0);
  63         testIntegerExact(1, 1);
  64         testIntegerExact(1, -1);
  65         testIntegerExact(-1, 1);
  66         testIntegerExact(1000, 2000);
  67 
  68         testIntegerExact(Integer.MIN_VALUE, Integer.MIN_VALUE);
  69         testIntegerExact(Integer.MAX_VALUE, Integer.MAX_VALUE);
  70         testIntegerExact(Integer.MIN_VALUE, 1);
  71         testIntegerExact(Integer.MAX_VALUE, 1);
  72         testIntegerExact(Integer.MIN_VALUE, 2);
  73         testIntegerExact(Integer.MAX_VALUE, 2);
  74         testIntegerExact(Integer.MIN_VALUE, -1);
  75         testIntegerExact(Integer.MAX_VALUE, -1);
  76         testIntegerExact(Integer.MIN_VALUE, -2);
  77         testIntegerExact(Integer.MAX_VALUE, -2);

  78     }
  79 
  80     /**
  81      * Test exact arithmetic by comparing with the same operations using long
  82      * and checking that the result is the same as the integer truncation.
  83      * Errors are reported with {@link fail}.
  84      *
  85      * @param x first parameter
  86      * @param y second parameter
  87      */
  88     static void testIntegerExact(int x, int y) {
  89         try {
  90             // Test addExact
  91             int sum = StrictMath.addExact(x, y);
  92             long sum2 = (long) x + (long) y;
  93             if ((int) sum2 != sum2) {
  94                 fail("FAIL: int StrictMath.addExact(" + x + " + " + y + ") = " + sum + "; expected Arithmetic exception");
  95             } else if (sum != sum2) {
  96                 fail("FAIL: long StrictMath.addExact(" + x + " + " + y + ") = " + sum + "; expected: " + sum2);
  97             }
  98         } catch (ArithmeticException ex) {
  99             long sum2 = (long) x + (long) y;
 100             if ((int) sum2 == sum2) {
 101                 fail("FAIL: int StrictMath.addExact(" + x + " + " + y + ")" + "; Unexpected exception: " + ex);

 102             }
 103         }
 104 
 105         try {
 106             // Test subtractExact
 107             int diff = StrictMath.subtractExact(x, y);
 108             long diff2 = (long) x - (long) y;
 109             if ((int) diff2 != diff2) {
 110                 fail("FAIL: int StrictMath.subtractExact(" + x + " - " + y + ") = " + diff + "; expected: " + diff2);
 111             }
 112 
 113         } catch (ArithmeticException ex) {
 114             long diff2 = (long) x - (long) y;
 115             if ((int) diff2 == diff2) {
 116                 fail("FAIL: int StrictMath.subtractExact(" + x + " - " + y + ")" + "; Unexpected exception: " + ex);
 117             }
 118         }
 119 
 120         try {
 121             // Test multiplyExact
 122             int product = StrictMath.multiplyExact(x, y);
 123             long m2 = (long) x * (long) y;
 124             if ((int) m2 != m2) {
 125                 fail("FAIL: int StrictMath.multiplyExact(" + x + " * " + y + ") = " + product + "; expected: " + m2);
 126             }
 127         } catch (ArithmeticException ex) {
 128             long m2 = (long) x * (long) y;
 129             if ((int) m2 == m2) {
 130                 fail("FAIL: int StrictMath.multiplyExact(" + x + " * " + y + ")" + "; Unexpected exception: " + ex);
 131             }
 132         }
 133 
 134         try {
 135             // Test incrementExact
 136             int inc = StrictMath.incrementExact(x);
 137             long inc2 = (long) x + 1L;
 138             if ((int) inc2 != inc2) {
 139                 fail("FAIL: int StrictMath.incrementExact(" + x + ") = " + inc + "; expected Arithmetic exception");
 140             } else if (inc != inc2) {
 141                 fail("FAIL: long StrictMath.incrementExact(" + x + ") = " + inc + "; expected: " + inc2);
 142             }
 143         } catch (ArithmeticException ex) {
 144             long inc2 = (long) x + 1L;
 145             if ((int) inc2 == inc2) {
 146                 fail("FAIL: int StrictMath.incrementExact(" + x + ")" + "; Unexpected exception: " + ex);
 147             }
 148         }
 149 
 150         try {
 151             // Test decrementExact
 152             int dec = StrictMath.decrementExact(x);
 153             long dec2 = (long) x - 1L;
 154             if ((int) dec2 != dec2) {
 155                 fail("FAIL: int StrictMath.decrementExact(" + x + ") = " + dec + "; expected Arithmetic exception");
 156             } else if (dec != dec2) {
 157                 fail("FAIL: long StrictMath.decrementExact(" + x + ") = " + dec + "; expected: " + dec2);
 158             }
 159         } catch (ArithmeticException ex) {
 160             long dec2 = (long) x - 1L;
 161             if ((int) dec2 == dec2) {
 162                 fail("FAIL: int StrictMath.decrementExact(" + x + ")" + "; Unexpected exception: " + ex);
 163             }
 164         }
 165 
 166         try {
 167             // Test negateExact
 168             int neg = StrictMath.negateExact(x);
 169             long neg2 = -((long)x) ;
 170             if ((int) neg2 != neg2) {
 171                 fail("FAIL: int StrictMath.negateExact(" + x + ") = " + neg + "; expected Arithmetic exception");
 172             } else if (neg != neg2) {
 173                 fail("FAIL: long StrictMath.negateExact(" + x + ") = " + neg + "; expected: " + neg2);
 174             }
 175         } catch (ArithmeticException ex) {
 176             long neg2 = (long) x - 1L;
 177             if ((int) neg2 == neg2) {
 178                 fail("FAIL: int StrictMath.negateExact(" + x + ")" + "; Unexpected exception: " + ex);
 179             }
 180         }
 181     }
 182 
 183     /**
 184      * Test StrictMath.addExact, multiplyExact, subtractExact, incrementExact,
 185      * decrementExact, negateExact, toIntExact methods with {@code long} arguments.
 186      */
 187     static void testLongExact() {
 188         testLongExactTwice(0, 0);
 189         testLongExactTwice(1, 1);
 190         testLongExactTwice(1, -1);
 191         testLongExactTwice(1000, 2000);
 192 
 193         testLongExactTwice(Long.MIN_VALUE, Long.MIN_VALUE);
 194         testLongExactTwice(Long.MAX_VALUE, Long.MAX_VALUE);
 195         testLongExactTwice(Long.MIN_VALUE, 1);
 196         testLongExactTwice(Long.MAX_VALUE, 1);
 197         testLongExactTwice(Long.MIN_VALUE, 2);
 198         testLongExactTwice(Long.MAX_VALUE, 2);
 199         testLongExactTwice(Long.MIN_VALUE, -1);
 200         testLongExactTwice(Long.MAX_VALUE, -1);
 201         testLongExactTwice(Long.MIN_VALUE, -2);
 202         testLongExactTwice(Long.MAX_VALUE, -2);
 203         testLongExactTwice(Long.MIN_VALUE/2, 2);
 204         testLongExactTwice(Long.MAX_VALUE, 2);
 205         testLongExactTwice(Integer.MAX_VALUE, Integer.MAX_VALUE);
 206         testLongExactTwice(Integer.MAX_VALUE, -Integer.MAX_VALUE);
 207         testLongExactTwice(Integer.MAX_VALUE+1, Integer.MAX_VALUE+1);
 208         testLongExactTwice(Integer.MAX_VALUE+1, -Integer.MAX_VALUE+1);
 209         testLongExactTwice(Integer.MIN_VALUE-1, Integer.MIN_VALUE-1);
 210         testLongExactTwice(Integer.MIN_VALUE-1, -Integer.MIN_VALUE-1);
 211         testLongExactTwice(Integer.MIN_VALUE/2, 2);

 212     }
 213 
 214     /**
 215      * Test each of the exact operations with the arguments and
 216      * with the arguments reversed.
 217      * @param x
 218      * @param y
 219      */
 220     static void testLongExactTwice(long x, long y) {
 221         testLongExact(x, y);
 222         testLongExact(y, x);
 223     }
 224 
 225 
 226     /**
 227      * Test long exact arithmetic by comparing with the same operations using BigInteger
 228      * and checking that the result is the same as the long truncation.
 229      * Errors are reported with {@link fail}.
 230      *
 231      * @param x first parameter
 232      * @param y second parameter
 233      */
 234     static void testLongExact(long x, long y) {
 235         BigInteger resultBig = null;
 236         final BigInteger xBig = BigInteger.valueOf(x);
 237         final BigInteger yBig = BigInteger.valueOf(y);
 238         try {
 239             // Test addExact
 240             resultBig = xBig.add(yBig);
 241             long sum = StrictMath.addExact(x, y);
 242             checkResult("long StrictMath.addExact", x, y, sum, resultBig);
 243         } catch (ArithmeticException ex) {
 244             if (inLongRange(resultBig)) {
 245                 fail("FAIL: long StrictMath.addExact(" + x + " + " + y + "); Unexpected exception: " + ex);
 246             }
 247         }
 248 
 249         try {
 250             // Test subtractExact
 251             resultBig = xBig.subtract(yBig);
 252             long diff = StrictMath.subtractExact(x, y);
 253             checkResult("long StrictMath.subtractExact", x, y, diff, resultBig);
 254         } catch (ArithmeticException ex) {
 255             if (inLongRange(resultBig)) {
 256                 fail("FAIL: long StrictMath.subtractExact(" + x + " - " + y + ")" + "; Unexpected exception: " + ex);
 257             }
 258         }
 259 
 260         try {
 261             // Test multiplyExact
 262             resultBig = xBig.multiply(yBig);
 263             long product = StrictMath.multiplyExact(x, y);
 264             checkResult("long StrictMath.multiplyExact", x, y, product, resultBig);
 265         } catch (ArithmeticException ex) {
 266             if (inLongRange(resultBig)) {
 267                 fail("FAIL: long StrictMath.multiplyExact(" + x + " * " + y + ")" + "; Unexpected exception: " + ex);
 268             }
 269         }
 270 
 271         try {
 272             // Test incrementExact
 273             resultBig = xBig.add(BigInteger.ONE);
 274             long inc = StrictMath.incrementExact(x);
 275             checkResult("long Math.incrementExact", x, 1L, inc, resultBig);
 276         } catch (ArithmeticException ex) {
 277             if (inLongRange(resultBig)) {
 278                 fail("FAIL: long Math.incrementExact(" + x + "); Unexpected exception: " + ex);
 279             }
 280         }
 281 
 282         try {
 283             // Test decrementExact
 284             resultBig = xBig.subtract(BigInteger.ONE);
 285             long dec = StrictMath.decrementExact(x);
 286             checkResult("long Math.decrementExact", x, 1L, dec, resultBig);
 287         } catch (ArithmeticException ex) {
 288             if (inLongRange(resultBig)) {
 289                 fail("FAIL: long Math.decrementExact(" + x + "); Unexpected exception: " + ex);
 290             }
 291         }
 292 
 293         try {
 294             // Test negateExact
 295             resultBig = xBig.negate();
 296             long dec = StrictMath.negateExact(x);
 297             checkResult("long Math.negateExact", x, 0L, dec, resultBig);
 298         } catch (ArithmeticException ex) {
 299             if (inLongRange(resultBig)) {
 300                 fail("FAIL: long Math.negateExact(" + x + "); Unexpected exception: " + ex);
 301             }
 302         }
 303 
 304         try {
 305             // Test toIntExact
 306             int value = StrictMath.toIntExact(x);
 307             if ((long)value != x) {
 308                 fail("FAIL: " + "long StrictMath.toIntExact" + "(" + x + ") = " + value + "; expected an arithmetic exception: ");
 309             }
 310         } catch (ArithmeticException ex) {
 311             if (resultBig.bitLength() <= 32) {
 312                 fail("FAIL: long StrictMath.toIntExact(" + x + ")" + "; Unexpected exception: " + ex);
 313             }
 314         }

 315     }
 316 
 317     /**
 318      * Compare the expected and actual results.
 319      * @param message message for the error
 320      * @param x first argument
 321      * @param y second argument
 322      * @param result actual result value
 323      * @param expected expected result value
 324      */
 325     static void checkResult(String message, long x, long y, long result, BigInteger expected) {
 326         BigInteger resultBig = BigInteger.valueOf(result);
 327         if (!inLongRange(expected)) {
 328             fail("FAIL: " + message + "(" + x + ", " + y + ") = " + result + "; expected an arithmetic exception: ");
 329         } else if (!resultBig.equals(expected)) {
 330             fail("FAIL: " + message + "(" + x + ", " + y + ") = " + result + "; expected " + expected);
 331         }
 332     }
 333 
 334     /**
 335      * Check if the value fits in 64 bits (a long).
 336      * @param value
 337      * @return true if the value fits in 64 bits (including the sign).
 338      */
 339     static boolean inLongRange(BigInteger value) {
 340         return value.bitLength() <= 63;
 341     }
 342 }
--- EOF ---