View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  package org.hipparchus.util;
23  
24  import java.math.BigInteger;
25  import java.util.ArrayList;
26  import java.util.Arrays;
27  
28  import org.hipparchus.exception.MathIllegalArgumentException;
29  import org.hipparchus.exception.MathRuntimeException;
30  import org.hipparchus.random.RandomDataGenerator;
31  import org.junit.Assert;
32  import org.junit.Test;
33  
34  /**
35   * Test cases for the {@link ArithmeticUtils} class.
36   */
37  public class ArithmeticUtilsTest {
38  
39      @Test
40      public void testAddAndCheck() {
41          int big = Integer.MAX_VALUE;
42          int bigNeg = Integer.MIN_VALUE;
43          Assert.assertEquals(big, ArithmeticUtils.addAndCheck(big, 0));
44          try {
45              ArithmeticUtils.addAndCheck(big, 1);
46              Assert.fail("Expecting MathRuntimeException");
47          } catch (MathRuntimeException ex) {
48          }
49          try {
50              ArithmeticUtils.addAndCheck(bigNeg, -1);
51              Assert.fail("Expecting MathRuntimeException");
52          } catch (MathRuntimeException ex) {
53          }
54      }
55  
56      @Test
57      public void testAddAndCheckLong() {
58          long max = Long.MAX_VALUE;
59          long min = Long.MIN_VALUE;
60          Assert.assertEquals(max, ArithmeticUtils.addAndCheck(max, 0L));
61          Assert.assertEquals(min, ArithmeticUtils.addAndCheck(min, 0L));
62          Assert.assertEquals(max, ArithmeticUtils.addAndCheck(0L, max));
63          Assert.assertEquals(min, ArithmeticUtils.addAndCheck(0L, min));
64          Assert.assertEquals(1, ArithmeticUtils.addAndCheck(-1L, 2L));
65          Assert.assertEquals(1, ArithmeticUtils.addAndCheck(2L, -1L));
66          Assert.assertEquals(-3, ArithmeticUtils.addAndCheck(-2L, -1L));
67          Assert.assertEquals(min, ArithmeticUtils.addAndCheck(min + 1, -1L));
68          Assert.assertEquals(-1, ArithmeticUtils.addAndCheck(min, max));
69          testAddAndCheckLongFailure(max, 1L);
70          testAddAndCheckLongFailure(min, -1L);
71          testAddAndCheckLongFailure(1L, max);
72          testAddAndCheckLongFailure(-1L, min);
73          testAddAndCheckLongFailure(max, max);
74          testAddAndCheckLongFailure(min, min);
75      }
76  
77      @Test
78      public void testGcd() {
79          int a = 30;
80          int b = 50;
81          int c = 77;
82  
83          Assert.assertEquals(0, ArithmeticUtils.gcd(0, 0));
84  
85          Assert.assertEquals(b, ArithmeticUtils.gcd(0, b));
86          Assert.assertEquals(a, ArithmeticUtils.gcd(a, 0));
87          Assert.assertEquals(b, ArithmeticUtils.gcd(0, -b));
88          Assert.assertEquals(a, ArithmeticUtils.gcd(-a, 0));
89  
90          Assert.assertEquals(10, ArithmeticUtils.gcd(a, b));
91          Assert.assertEquals(10, ArithmeticUtils.gcd(-a, b));
92          Assert.assertEquals(10, ArithmeticUtils.gcd(a, -b));
93          Assert.assertEquals(10, ArithmeticUtils.gcd(-a, -b));
94  
95          Assert.assertEquals(1, ArithmeticUtils.gcd(a, c));
96          Assert.assertEquals(1, ArithmeticUtils.gcd(-a, c));
97          Assert.assertEquals(1, ArithmeticUtils.gcd(a, -c));
98          Assert.assertEquals(1, ArithmeticUtils.gcd(-a, -c));
99  
100         Assert.assertEquals(3 * (1<<15), ArithmeticUtils.gcd(3 * (1<<20), 9 * (1<<15)));
101 
102         Assert.assertEquals(Integer.MAX_VALUE, ArithmeticUtils.gcd(Integer.MAX_VALUE, 0));
103         Assert.assertEquals(Integer.MAX_VALUE, ArithmeticUtils.gcd(-Integer.MAX_VALUE, 0));
104         Assert.assertEquals(1<<30, ArithmeticUtils.gcd(1<<30, -Integer.MIN_VALUE));
105         try {
106             // gcd(Integer.MIN_VALUE, 0) > Integer.MAX_VALUE
107             ArithmeticUtils.gcd(Integer.MIN_VALUE, 0);
108             Assert.fail("expecting MathRuntimeException");
109         } catch (MathRuntimeException expected) {
110             // expected
111         }
112         try {
113             // gcd(0, Integer.MIN_VALUE) > Integer.MAX_VALUE
114             ArithmeticUtils.gcd(0, Integer.MIN_VALUE);
115             Assert.fail("expecting MathRuntimeException");
116         } catch (MathRuntimeException expected) {
117             // expected
118         }
119         try {
120             // gcd(Integer.MIN_VALUE, Integer.MIN_VALUE) > Integer.MAX_VALUE
121             ArithmeticUtils.gcd(Integer.MIN_VALUE, Integer.MIN_VALUE);
122             Assert.fail("expecting MathRuntimeException");
123         } catch (MathRuntimeException expected) {
124             // expected
125         }
126     }
127 
128     @Test
129     public void testGcdConsistency() {
130         int[] primeList = {19, 23, 53, 67, 73, 79, 101, 103, 111, 131};
131         ArrayList<Integer> primes = new ArrayList<Integer>();
132         for (int i = 0; i < primeList.length; i++) {
133             primes.add(Integer.valueOf(primeList[i]));
134         }
135         RandomDataGenerator randomData = new RandomDataGenerator();
136         for (int i = 0; i < 20; i++) {
137             Object[] sample = randomData.nextSample(primes, 4);
138             int p1 = ((Integer) sample[0]).intValue();
139             int p2 = ((Integer) sample[1]).intValue();
140             int p3 = ((Integer) sample[2]).intValue();
141             int p4 = ((Integer) sample[3]).intValue();
142             int i1 = p1 * p2 * p3;
143             int i2 = p1 * p2 * p4;
144             int gcd = p1 * p2;
145             Assert.assertEquals(gcd, ArithmeticUtils.gcd(i1, i2));
146             long l1 = i1;
147             long l2 = i2;
148             Assert.assertEquals(gcd, ArithmeticUtils.gcd(l1, l2));
149         }
150     }
151 
152     @Test
153     public void  testGcdLong(){
154         long a = 30;
155         long b = 50;
156         long c = 77;
157 
158         Assert.assertEquals(0, ArithmeticUtils.gcd(0L, 0));
159 
160         Assert.assertEquals(b, ArithmeticUtils.gcd(0, b));
161         Assert.assertEquals(a, ArithmeticUtils.gcd(a, 0));
162         Assert.assertEquals(b, ArithmeticUtils.gcd(0, -b));
163         Assert.assertEquals(a, ArithmeticUtils.gcd(-a, 0));
164 
165         Assert.assertEquals(10, ArithmeticUtils.gcd(a, b));
166         Assert.assertEquals(10, ArithmeticUtils.gcd(-a, b));
167         Assert.assertEquals(10, ArithmeticUtils.gcd(a, -b));
168         Assert.assertEquals(10, ArithmeticUtils.gcd(-a, -b));
169 
170         Assert.assertEquals(1, ArithmeticUtils.gcd(a, c));
171         Assert.assertEquals(1, ArithmeticUtils.gcd(-a, c));
172         Assert.assertEquals(1, ArithmeticUtils.gcd(a, -c));
173         Assert.assertEquals(1, ArithmeticUtils.gcd(-a, -c));
174 
175         Assert.assertEquals(3L * (1L<<45), ArithmeticUtils.gcd(3L * (1L<<50), 9L * (1L<<45)));
176 
177         Assert.assertEquals(1L<<45, ArithmeticUtils.gcd(1L<<45, Long.MIN_VALUE));
178 
179         Assert.assertEquals(Long.MAX_VALUE, ArithmeticUtils.gcd(Long.MAX_VALUE, 0L));
180         Assert.assertEquals(Long.MAX_VALUE, ArithmeticUtils.gcd(-Long.MAX_VALUE, 0L));
181         Assert.assertEquals(1, ArithmeticUtils.gcd(60247241209L, 153092023L));
182         try {
183             // gcd(Long.MIN_VALUE, 0) > Long.MAX_VALUE
184             ArithmeticUtils.gcd(Long.MIN_VALUE, 0);
185             Assert.fail("expecting MathRuntimeException");
186         } catch (MathRuntimeException expected) {
187             // expected
188         }
189         try {
190             // gcd(0, Long.MIN_VALUE) > Long.MAX_VALUE
191             ArithmeticUtils.gcd(0, Long.MIN_VALUE);
192             Assert.fail("expecting MathRuntimeException");
193         } catch (MathRuntimeException expected) {
194             // expected
195         }
196         try {
197             // gcd(Long.MIN_VALUE, Long.MIN_VALUE) > Long.MAX_VALUE
198             ArithmeticUtils.gcd(Long.MIN_VALUE, Long.MIN_VALUE);
199             Assert.fail("expecting MathRuntimeException");
200         } catch (MathRuntimeException expected) {
201             // expected
202         }
203     }
204 
205 
206     @Test
207     public void testLcm() {
208         int a = 30;
209         int b = 50;
210         int c = 77;
211 
212         Assert.assertEquals(0, ArithmeticUtils.lcm(0, b));
213         Assert.assertEquals(0, ArithmeticUtils.lcm(a, 0));
214         Assert.assertEquals(b, ArithmeticUtils.lcm(1, b));
215         Assert.assertEquals(a, ArithmeticUtils.lcm(a, 1));
216         Assert.assertEquals(150, ArithmeticUtils.lcm(a, b));
217         Assert.assertEquals(150, ArithmeticUtils.lcm(-a, b));
218         Assert.assertEquals(150, ArithmeticUtils.lcm(a, -b));
219         Assert.assertEquals(150, ArithmeticUtils.lcm(-a, -b));
220         Assert.assertEquals(2310, ArithmeticUtils.lcm(a, c));
221 
222         // Assert that no intermediate value overflows:
223         // The naive implementation of lcm(a,b) would be (a*b)/gcd(a,b)
224         Assert.assertEquals((1<<20)*15, ArithmeticUtils.lcm((1<<20)*3, (1<<20)*5));
225 
226         // Special case
227         Assert.assertEquals(0, ArithmeticUtils.lcm(0, 0));
228 
229         try {
230             // lcm == abs(MIN_VALUE) cannot be represented as a nonnegative int
231             ArithmeticUtils.lcm(Integer.MIN_VALUE, 1);
232             Assert.fail("Expecting MathRuntimeException");
233         } catch (MathRuntimeException expected) {
234             // expected
235         }
236 
237         try {
238             // lcm == abs(MIN_VALUE) cannot be represented as a nonnegative int
239             ArithmeticUtils.lcm(Integer.MIN_VALUE, 1<<20);
240             Assert.fail("Expecting MathRuntimeException");
241         } catch (MathRuntimeException expected) {
242             // expected
243         }
244 
245         try {
246             ArithmeticUtils.lcm(Integer.MAX_VALUE, Integer.MAX_VALUE - 1);
247             Assert.fail("Expecting MathRuntimeException");
248         } catch (MathRuntimeException expected) {
249             // expected
250         }
251     }
252 
253     @Test
254     public void testLcmLong() {
255         long a = 30;
256         long b = 50;
257         long c = 77;
258 
259         Assert.assertEquals(0, ArithmeticUtils.lcm(0, b));
260         Assert.assertEquals(0, ArithmeticUtils.lcm(a, 0));
261         Assert.assertEquals(b, ArithmeticUtils.lcm(1, b));
262         Assert.assertEquals(a, ArithmeticUtils.lcm(a, 1));
263         Assert.assertEquals(150, ArithmeticUtils.lcm(a, b));
264         Assert.assertEquals(150, ArithmeticUtils.lcm(-a, b));
265         Assert.assertEquals(150, ArithmeticUtils.lcm(a, -b));
266         Assert.assertEquals(150, ArithmeticUtils.lcm(-a, -b));
267         Assert.assertEquals(2310, ArithmeticUtils.lcm(a, c));
268 
269         Assert.assertEquals(Long.MAX_VALUE, ArithmeticUtils.lcm(60247241209L, 153092023L));
270 
271         // Assert that no intermediate value overflows:
272         // The naive implementation of lcm(a,b) would be (a*b)/gcd(a,b)
273         Assert.assertEquals((1L<<50)*15, ArithmeticUtils.lcm((1L<<45)*3, (1L<<50)*5));
274 
275         // Special case
276         Assert.assertEquals(0L, ArithmeticUtils.lcm(0L, 0L));
277 
278         try {
279             // lcm == abs(MIN_VALUE) cannot be represented as a nonnegative int
280             ArithmeticUtils.lcm(Long.MIN_VALUE, 1);
281             Assert.fail("Expecting MathRuntimeException");
282         } catch (MathRuntimeException expected) {
283             // expected
284         }
285 
286         try {
287             // lcm == abs(MIN_VALUE) cannot be represented as a nonnegative int
288             ArithmeticUtils.lcm(Long.MIN_VALUE, 1<<20);
289             Assert.fail("Expecting MathRuntimeException");
290         } catch (MathRuntimeException expected) {
291             // expected
292         }
293 
294         Assert.assertEquals((long) Integer.MAX_VALUE * (Integer.MAX_VALUE - 1),
295             ArithmeticUtils.lcm((long)Integer.MAX_VALUE, Integer.MAX_VALUE - 1));
296         try {
297             ArithmeticUtils.lcm(Long.MAX_VALUE, Long.MAX_VALUE - 1);
298             Assert.fail("Expecting MathRuntimeException");
299         } catch (MathRuntimeException expected) {
300             // expected
301         }
302     }
303 
304     @Test
305     public void testMulAndCheck() {
306         int big = Integer.MAX_VALUE;
307         int bigNeg = Integer.MIN_VALUE;
308         Assert.assertEquals(big, ArithmeticUtils.mulAndCheck(big, 1));
309         try {
310             ArithmeticUtils.mulAndCheck(big, 2);
311             Assert.fail("Expecting MathRuntimeException");
312         } catch (MathRuntimeException ex) {
313         }
314         try {
315             ArithmeticUtils.mulAndCheck(bigNeg, 2);
316             Assert.fail("Expecting MathRuntimeException");
317         } catch (MathRuntimeException ex) {
318         }
319     }
320 
321     @Test
322     public void testMulAndCheckLong() {
323         long max = Long.MAX_VALUE;
324         long min = Long.MIN_VALUE;
325         Assert.assertEquals(max, ArithmeticUtils.mulAndCheck(max, 1L));
326         Assert.assertEquals(min, ArithmeticUtils.mulAndCheck(min, 1L));
327         Assert.assertEquals(0L, ArithmeticUtils.mulAndCheck(max, 0L));
328         Assert.assertEquals(0L, ArithmeticUtils.mulAndCheck(min, 0L));
329         Assert.assertEquals(max, ArithmeticUtils.mulAndCheck(1L, max));
330         Assert.assertEquals(min, ArithmeticUtils.mulAndCheck(1L, min));
331         Assert.assertEquals(0L, ArithmeticUtils.mulAndCheck(0L, max));
332         Assert.assertEquals(0L, ArithmeticUtils.mulAndCheck(0L, min));
333         Assert.assertEquals(1L, ArithmeticUtils.mulAndCheck(-1L, -1L));
334         Assert.assertEquals(min, ArithmeticUtils.mulAndCheck(min / 2, 2));
335         testMulAndCheckLongFailure(max, 2L);
336         testMulAndCheckLongFailure(2L, max);
337         testMulAndCheckLongFailure(min, 2L);
338         testMulAndCheckLongFailure(2L, min);
339         testMulAndCheckLongFailure(min, -1L);
340         testMulAndCheckLongFailure(-1L, min);
341     }
342 
343     @Test
344     public void testSubAndCheck() {
345         int big = Integer.MAX_VALUE;
346         int bigNeg = Integer.MIN_VALUE;
347         Assert.assertEquals(big, ArithmeticUtils.subAndCheck(big, 0));
348         Assert.assertEquals(bigNeg + 1, ArithmeticUtils.subAndCheck(bigNeg, -1));
349         Assert.assertEquals(-1, ArithmeticUtils.subAndCheck(bigNeg, -big));
350         try {
351             ArithmeticUtils.subAndCheck(big, -1);
352             Assert.fail("Expecting MathRuntimeException");
353         } catch (MathRuntimeException ex) {
354         }
355         try {
356             ArithmeticUtils.subAndCheck(bigNeg, 1);
357             Assert.fail("Expecting MathRuntimeException");
358         } catch (MathRuntimeException ex) {
359         }
360     }
361 
362     @Test
363     public void testSubAndCheckErrorMessage() {
364         int big = Integer.MAX_VALUE;
365         try {
366             ArithmeticUtils.subAndCheck(big, -1);
367             Assert.fail("Expecting MathRuntimeException");
368         } catch (MathRuntimeException ex) {
369             Assert.assertTrue(ex.getMessage().length() > 1);
370         }
371     }
372 
373     @Test
374     public void testSubAndCheckLong() {
375         long max = Long.MAX_VALUE;
376         long min = Long.MIN_VALUE;
377         Assert.assertEquals(max, ArithmeticUtils.subAndCheck(max, 0));
378         Assert.assertEquals(min, ArithmeticUtils.subAndCheck(min, 0));
379         Assert.assertEquals(-max, ArithmeticUtils.subAndCheck(0, max));
380         Assert.assertEquals(min + 1, ArithmeticUtils.subAndCheck(min, -1));
381         // min == -1-max
382         Assert.assertEquals(-1, ArithmeticUtils.subAndCheck(-max - 1, -max));
383         Assert.assertEquals(max, ArithmeticUtils.subAndCheck(-1, -1 - max));
384         testSubAndCheckLongFailure(0L, min);
385         testSubAndCheckLongFailure(max, -1L);
386         testSubAndCheckLongFailure(min, 1L);
387     }
388 
389     @Test
390     public void testPow() {
391 
392         Assert.assertEquals(1801088541, ArithmeticUtils.pow(21, 7));
393         Assert.assertEquals(1, ArithmeticUtils.pow(21, 0));
394         try {
395             ArithmeticUtils.pow(21, -7);
396             Assert.fail("Expecting MathIllegalArgumentException");
397         } catch (MathIllegalArgumentException e) {
398             // expected behavior
399         }
400 
401         Assert.assertEquals(1801088541, ArithmeticUtils.pow(21, 7));
402         Assert.assertEquals(1, ArithmeticUtils.pow(21, 0));
403         try {
404             ArithmeticUtils.pow(21, -7);
405             Assert.fail("Expecting MathIllegalArgumentException");
406         } catch (MathIllegalArgumentException e) {
407             // expected behavior
408         }
409 
410         Assert.assertEquals(1801088541L, ArithmeticUtils.pow(21L, 7));
411         Assert.assertEquals(1L, ArithmeticUtils.pow(21L, 0));
412         try {
413             ArithmeticUtils.pow(21L, -7);
414             Assert.fail("Expecting MathIllegalArgumentException");
415         } catch (MathIllegalArgumentException e) {
416             // expected behavior
417         }
418 
419         BigInteger twentyOne = BigInteger.valueOf(21L);
420         Assert.assertEquals(BigInteger.valueOf(1801088541L), ArithmeticUtils.pow(twentyOne, 7));
421         Assert.assertEquals(BigInteger.ONE, ArithmeticUtils.pow(twentyOne, 0));
422         try {
423             ArithmeticUtils.pow(twentyOne, -7);
424             Assert.fail("Expecting MathIllegalArgumentException");
425         } catch (MathIllegalArgumentException e) {
426             // expected behavior
427         }
428 
429         Assert.assertEquals(BigInteger.valueOf(1801088541L), ArithmeticUtils.pow(twentyOne,
430                                                                                  7L));
431         Assert.assertEquals(BigInteger.ONE, ArithmeticUtils.pow(twentyOne, 0L));
432         try {
433             ArithmeticUtils.pow(twentyOne, -7L);
434             Assert.fail("Expecting MathIllegalArgumentException");
435         } catch (MathIllegalArgumentException e) {
436             // expected behavior
437         }
438 
439         Assert.assertEquals(BigInteger.valueOf(1801088541L), ArithmeticUtils.pow(twentyOne, BigInteger.valueOf(
440                         7L)));
441         Assert.assertEquals(BigInteger.ONE, ArithmeticUtils.pow(twentyOne, BigInteger.ZERO));
442         try {
443             ArithmeticUtils.pow(twentyOne, BigInteger.valueOf(-7L));
444             Assert.fail("Expecting MathIllegalArgumentException");
445         } catch (MathIllegalArgumentException e) {
446             // expected behavior
447         }
448 
449         BigInteger bigOne =
450             new BigInteger("1543786922199448028351389769265814882661837148" +
451                            "4763915343722775611762713982220306372888519211" +
452                            "560905579993523402015636025177602059044911261");
453         Assert.assertEquals(bigOne, ArithmeticUtils.pow(twentyOne, 103));
454         Assert.assertEquals(bigOne, ArithmeticUtils.pow(twentyOne, 103L));
455         Assert.assertEquals(bigOne, ArithmeticUtils.pow(twentyOne, BigInteger.valueOf(
456                         103L)));
457 
458     }
459 
460     @Test(expected=MathRuntimeException.class)
461     public void testPowIntOverflow() {
462         ArithmeticUtils.pow(21, 8);
463     }
464 
465     @Test
466     public void testPowInt() {
467         final int base = 21;
468 
469         Assert.assertEquals(85766121L,
470                             ArithmeticUtils.pow(base, 6));
471         Assert.assertEquals(1801088541L,
472                             ArithmeticUtils.pow(base, 7));
473     }
474 
475     @Test(expected=MathRuntimeException.class)
476     public void testPowNegativeIntOverflow() {
477         ArithmeticUtils.pow(-21, 8);
478     }
479 
480     @Test
481     public void testPowNegativeInt() {
482         final int base = -21;
483 
484         Assert.assertEquals(85766121,
485                             ArithmeticUtils.pow(base, 6));
486         Assert.assertEquals(-1801088541,
487                             ArithmeticUtils.pow(base, 7));
488     }
489 
490     @Test
491     public void testPowMinusOneInt() {
492         final int base = -1;
493         for (int i = 0; i < 100; i++) {
494             final int pow = ArithmeticUtils.pow(base, i);
495             Assert.assertEquals("i: " + i, i % 2 == 0 ? 1 : -1, pow);
496         }
497     }
498 
499     @Test
500     public void testPowOneInt() {
501         final int base = 1;
502         for (int i = 0; i < 100; i++) {
503             final int pow = ArithmeticUtils.pow(base, i);
504             Assert.assertEquals("i: " + i, 1, pow);
505         }
506     }
507 
508     @Test(expected=MathRuntimeException.class)
509     public void testPowLongOverflow() {
510         ArithmeticUtils.pow(21, 15);
511     }
512 
513     @Test
514     public void testPowLong() {
515         final long base = 21;
516 
517         Assert.assertEquals(154472377739119461L,
518                             ArithmeticUtils.pow(base, 13));
519         Assert.assertEquals(3243919932521508681L,
520                             ArithmeticUtils.pow(base, 14));
521     }
522 
523     @Test(expected=MathRuntimeException.class)
524     public void testPowNegativeLongOverflow() {
525         ArithmeticUtils.pow(-21L, 15);
526     }
527 
528     @Test
529     public void testPowNegativeLong() {
530         final long base = -21;
531 
532         Assert.assertEquals(-154472377739119461L,
533                             ArithmeticUtils.pow(base, 13));
534         Assert.assertEquals(3243919932521508681L,
535                             ArithmeticUtils.pow(base, 14));
536     }
537 
538     @Test
539     public void testPowMinusOneLong() {
540         final long base = -1;
541         for (int i = 0; i < 100; i++) {
542             final long pow = ArithmeticUtils.pow(base, i);
543             Assert.assertEquals("i: " + i, i % 2 == 0 ? 1 : -1, pow);
544         }
545     }
546 
547     @Test
548     public void testPowOneLong() {
549         final long base = 1;
550         for (int i = 0; i < 100; i++) {
551             final long pow = ArithmeticUtils.pow(base, i);
552             Assert.assertEquals("i: " + i, 1, pow);
553         }
554     }
555 
556     @Test
557     public void testIsPowerOfTwo() {
558         final int n = 1025;
559         final boolean[] expected = new boolean[n];
560         Arrays.fill(expected, false);
561         for (int i = 1; i < expected.length; i *= 2) {
562             expected[i] = true;
563         }
564         for (int i = 0; i < expected.length; i++) {
565             final boolean actual = ArithmeticUtils.isPowerOfTwo(i);
566             Assert.assertEquals(Integer.toString(i), actual, expected[i]);
567         }
568     }
569 
570     private void testAddAndCheckLongFailure(long a, long b) {
571         try {
572             ArithmeticUtils.addAndCheck(a, b);
573             Assert.fail("Expecting MathRuntimeException");
574         } catch (MathRuntimeException ex) {
575             // success
576         }
577     }
578 
579     private void testMulAndCheckLongFailure(long a, long b) {
580         try {
581             ArithmeticUtils.mulAndCheck(a, b);
582             Assert.fail("Expecting MathRuntimeException");
583         } catch (MathRuntimeException ex) {
584             // success
585         }
586     }
587 
588     private void testSubAndCheckLongFailure(long a, long b) {
589         try {
590             ArithmeticUtils.subAndCheck(a, b);
591             Assert.fail("Expecting MathRuntimeException");
592         } catch (MathRuntimeException ex) {
593             // success
594         }
595     }
596 
597     /**
598      * Testing helper method.
599      * @return an array of int numbers containing corner cases:<ul>
600      * <li>values near the beginning of int range,</li>
601      * <li>values near the end of int range,</li>
602      * <li>values near zero</li>
603      * <li>and some randomly distributed values.</li>
604      * </ul>
605      */
606     private static int[] getIntSpecialCases() {
607         int[] ints = new int[100];
608         int i = 0;
609         ints[i++] = Integer.MAX_VALUE;
610         ints[i++] = Integer.MAX_VALUE - 1;
611         ints[i++] = 100;
612         ints[i++] = 101;
613         ints[i++] = 102;
614         ints[i++] = 300;
615         ints[i++] = 567;
616         for (int j = 0; j < 20; j++) {
617             ints[i++] = j;
618         }
619         for (int j = i - 1; j >= 0; j--) {
620             ints[i++] = ints[j] > 0 ? -ints[j] : Integer.MIN_VALUE;
621         }
622         java.util.Random r = new java.util.Random(System.nanoTime());
623         while (i < ints.length) {
624             ints[i++] = r.nextInt();
625         }
626         return ints;
627     }
628 
629     /**
630      * Testing helper method.
631      * @return an array of long numbers containing corner cases:<ul>
632      * <li>values near the beginning of long range,</li>
633      * <li>values near the end of long range,</li>
634      * <li>values near the beginning of int range,</li>
635      * <li>values near the end of int range,</li>
636      * <li>values near zero</li>
637      * <li>and some randomly distributed values.</li>
638      * </ul>
639      */
640     private static long[] getLongSpecialCases() {
641         long[] longs = new long[100];
642         int i = 0;
643         longs[i++] = Long.MAX_VALUE;
644         longs[i++] = Long.MAX_VALUE - 1L;
645         longs[i++] = (long) Integer.MAX_VALUE + 1L;
646         longs[i++] = Integer.MAX_VALUE;
647         longs[i++] = Integer.MAX_VALUE - 1;
648         longs[i++] = 100L;
649         longs[i++] = 101L;
650         longs[i++] = 102L;
651         longs[i++] = 300L;
652         longs[i++] = 567L;
653         for (int j = 0; j < 20; j++) {
654             longs[i++] = j;
655         }
656         for (int j = i - 1; j >= 0; j--) {
657             longs[i++] = longs[j] > 0L ? -longs[j] : Long.MIN_VALUE;
658         }
659         java.util.Random r = new java.util.Random(System.nanoTime());
660         while (i < longs.length) {
661             longs[i++] = r.nextLong();
662         }
663         return longs;
664     }
665 
666     private static long toUnsignedLong(int number) {
667         return number < 0 ? 0x100000000L + (long)number : (long)number;
668     }
669 
670     private static int remainderUnsignedExpected(int dividend, int divisor) {
671         return (int)remainderUnsignedExpected(toUnsignedLong(dividend), toUnsignedLong(divisor));
672     }
673 
674     private static int divideUnsignedExpected(int dividend, int divisor) {
675         return (int)divideUnsignedExpected(toUnsignedLong(dividend), toUnsignedLong(divisor));
676     }
677 
678     private static BigInteger toUnsignedBigInteger(long number) {
679         return number < 0L ? BigInteger.ONE.shiftLeft(64).add(BigInteger.valueOf(number)) : BigInteger.valueOf(number);
680     }
681 
682     private static long remainderUnsignedExpected(long dividend, long divisor) {
683         return toUnsignedBigInteger(dividend).remainder(toUnsignedBigInteger(divisor)).longValue();
684     }
685 
686     private static long divideUnsignedExpected(long dividend, long divisor) {
687         return toUnsignedBigInteger(dividend).divide(toUnsignedBigInteger(divisor)).longValue();
688     }
689 
690     @Test(timeout=5000L)
691     public void testRemainderUnsignedInt() {
692         Assert.assertEquals(36, ArithmeticUtils.remainderUnsigned(-2147479015, 63));
693         Assert.assertEquals(6, ArithmeticUtils.remainderUnsigned(-2147479015, 25));
694     }
695 
696     @Test(timeout=5000L)
697     public void testRemainderUnsignedIntSpecialCases() {
698         int[] ints = getIntSpecialCases();
699         for (int dividend : ints) {
700             for (int divisor : ints) {
701                 if (divisor == 0) {
702                     try {
703                         ArithmeticUtils.remainderUnsigned(dividend, divisor);
704                         Assert.fail("Should have failed with ArithmeticException: division by zero");
705                     } catch (ArithmeticException e) {
706                         // Success.
707                     }
708                 } else {
709                     Assert.assertEquals(remainderUnsignedExpected(dividend, divisor), ArithmeticUtils.remainderUnsigned(dividend, divisor));
710                 }
711             }
712         }
713     }
714 
715     @Test(timeout=5000L)
716     public void testRemainderUnsignedLong() {
717         Assert.assertEquals(48L, ArithmeticUtils.remainderUnsigned(-2147479015L, 63L));
718     }
719 
720     @Test//(timeout=5000L)
721     public void testRemainderUnsignedLongSpecialCases() {
722         long[] longs = getLongSpecialCases();
723         for (long dividend : longs) {
724             for (long divisor : longs) {
725                 if (divisor == 0L) {
726                     try {
727                         ArithmeticUtils.remainderUnsigned(dividend, divisor);
728                         Assert.fail("Should have failed with ArithmeticException: division by zero");
729                     } catch (ArithmeticException e) {
730                         // Success.
731                     }
732                 } else {
733                     Assert.assertEquals(remainderUnsignedExpected(dividend, divisor), ArithmeticUtils.remainderUnsigned(dividend, divisor));
734                 }
735             }
736         }
737     }
738 
739     @Test(timeout=5000L)
740     public void testDivideUnsignedInt() {
741         Assert.assertEquals(34087115, ArithmeticUtils.divideUnsigned(-2147479015, 63));
742         Assert.assertEquals(85899531, ArithmeticUtils.divideUnsigned(-2147479015, 25));
743         Assert.assertEquals(2147483646, ArithmeticUtils.divideUnsigned(-3, 2));
744         Assert.assertEquals(330382098, ArithmeticUtils.divideUnsigned(-16, 13));
745         Assert.assertEquals(306783377, ArithmeticUtils.divideUnsigned(-16, 14));
746         Assert.assertEquals(2, ArithmeticUtils.divideUnsigned(-1, 2147483647));
747         Assert.assertEquals(2, ArithmeticUtils.divideUnsigned(-2, 2147483647));
748         Assert.assertEquals(1, ArithmeticUtils.divideUnsigned(-3, 2147483647));
749         Assert.assertEquals(1, ArithmeticUtils.divideUnsigned(-16, 2147483647));
750         Assert.assertEquals(1, ArithmeticUtils.divideUnsigned(-16, 2147483646));
751     }
752 
753     @Test(timeout=5000L)
754     public void testDivideUnsignedIntSpecialCases() {
755         int[] ints = getIntSpecialCases();
756         for (int dividend : ints) {
757             for (int divisor : ints) {
758                 if (divisor == 0) {
759                     try {
760                         ArithmeticUtils.divideUnsigned(dividend, divisor);
761                         Assert.fail("Should have failed with ArithmeticException: division by zero");
762                     } catch (ArithmeticException e) {
763                         // Success.
764                     }
765                 } else {
766                     Assert.assertEquals(divideUnsignedExpected(dividend, divisor), ArithmeticUtils.divideUnsigned(dividend, divisor));
767                 }
768             }
769         }
770     }
771 
772     @Test(timeout=5000L)
773     public void testDivideUnsignedLong() {
774         Assert.assertEquals(292805461453366231L, ArithmeticUtils.divideUnsigned(-2147479015L, 63L));
775     }
776 
777     @Test(timeout=5000L)
778     public void testDivideUnsignedLongSpecialCases() {
779         long[] longs = getLongSpecialCases();
780         for (long dividend : longs) {
781             for (long divisor : longs) {
782                 if (divisor == 0L) {
783                     try {
784                         ArithmeticUtils.divideUnsigned(dividend, divisor);
785                         Assert.fail("Should have failed with ArithmeticException: division by zero");
786                     } catch (ArithmeticException e) {
787                         // Success.
788                     }
789                 } else {
790                     Assert.assertEquals(divideUnsignedExpected(dividend, divisor), ArithmeticUtils.divideUnsigned(dividend, divisor));
791                 }
792             }
793         }
794     }
795 }