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
24import 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 */
33public 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}
407