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.fraction;
23  
24  import org.hipparchus.UnitTestUtils;
25  import org.hipparchus.exception.MathIllegalArgumentException;
26  import org.hipparchus.exception.MathIllegalStateException;
27  import org.hipparchus.exception.MathRuntimeException;
28  import org.hipparchus.exception.NullArgumentException;
29  import org.hipparchus.util.FastMath;
30  import org.hipparchus.util.Precision;
31  import org.junit.jupiter.api.Test;
32  
33  import java.math.BigDecimal;
34  import java.math.BigInteger;
35  import java.math.RoundingMode;
36  import java.util.List;
37  import java.util.stream.Collectors;
38  
39  import static org.junit.jupiter.api.Assertions.assertEquals;
40  import static org.junit.jupiter.api.Assertions.assertFalse;
41  import static org.junit.jupiter.api.Assertions.assertNotEquals;
42  import static org.junit.jupiter.api.Assertions.assertSame;
43  import static org.junit.jupiter.api.Assertions.assertThrows;
44  import static org.junit.jupiter.api.Assertions.assertTrue;
45  import static org.junit.jupiter.api.Assertions.fail;
46  
47  
48  class BigFractionTest {
49  
50      private void customCustomAssertFraction(int expectedNumerator, int expectedDenominator, BigFraction actual) {
51          assertEquals(expectedNumerator, actual.getNumeratorAsInt());
52          assertEquals(expectedDenominator, actual.getDenominatorAsInt());
53      }
54  
55      private void customCustomAssertFraction(long expectedNumerator, long expectedDenominator, BigFraction actual) {
56          assertEquals(expectedNumerator, actual.getNumeratorAsLong());
57          assertEquals(expectedDenominator, actual.getDenominatorAsLong());
58      }
59  
60      @Test
61      void testConstructor() {
62          customCustomAssertFraction(0, 1, new BigFraction(0, 1));
63          customCustomAssertFraction(0, 1, new BigFraction(0l, 2l));
64          customCustomAssertFraction(0, 1, new BigFraction(0, -1));
65          customCustomAssertFraction(1, 2, new BigFraction(1, 2));
66          customCustomAssertFraction(1, 2, new BigFraction(2, 4));
67          customCustomAssertFraction(-1, 2, new BigFraction(-1, 2));
68          customCustomAssertFraction(-1, 2, new BigFraction(1, -2));
69          customCustomAssertFraction(-1, 2, new BigFraction(-2, 4));
70          customCustomAssertFraction(-1, 2, new BigFraction(2, -4));
71          customCustomAssertFraction(11, 1, new BigFraction(11));
72          customCustomAssertFraction(11, 1, new BigFraction(11l));
73          customCustomAssertFraction(11, 1, new BigFraction(new BigInteger("11")));
74  
75          customCustomAssertFraction(0, 1, new BigFraction(0.00000000000001, 1.0e-5, 100));
76          customCustomAssertFraction(2, 5, new BigFraction(0.40000000000001, 1.0e-5, 100));
77          customCustomAssertFraction(15, 1, new BigFraction(15.0000000000001, 1.0e-5, 100));
78  
79          assertEquals(0.00000000000001, new BigFraction(0.00000000000001).doubleValue(), 0.0);
80          assertEquals(0.40000000000001, new BigFraction(0.40000000000001).doubleValue(), 0.0);
81          assertEquals(15.0000000000001, new BigFraction(15.0000000000001).doubleValue(), 0.0);
82          customCustomAssertFraction(3602879701896487l, 9007199254740992l, new BigFraction(0.40000000000001));
83          customCustomAssertFraction(1055531162664967l, 70368744177664l, new BigFraction(15.0000000000001));
84          try {
85              new BigFraction(null, BigInteger.ONE);
86              fail("Expecting NullArgumentException");
87          } catch (NullArgumentException npe) {
88              // expected
89          }
90          try {
91              new BigFraction(BigInteger.ONE, null);
92              fail("Expecting NullArgumentException");
93          } catch (NullArgumentException npe) {
94              // expected
95          }
96          try {
97              new BigFraction(BigInteger.ONE, BigInteger.ZERO);
98              fail("Expecting MathIllegalArgumentException");
99          } catch (MathIllegalArgumentException npe) {
100             // expected
101         }
102     }
103 
104     @Test
105     void testIsInteger() {
106         assertTrue(new BigFraction(12, 12).isInteger());
107         assertTrue(new BigFraction(14, 7).isInteger());
108         assertFalse(new BigFraction(12, 11).isInteger());
109     }
110 
111     @Test
112     void testGoldenRatio() {
113         assertThrows(MathIllegalStateException.class, () -> {
114             // the golden ratio is notoriously a difficult number for continuous fraction
115             new BigFraction((1 + FastMath.sqrt(5)) / 2, 1.0e-12, 25);
116         });
117     }
118 
119     // MATH-179
120     @Test
121     void testDoubleConstructor() throws MathIllegalStateException {
122         customCustomAssertFraction(1, 2, new BigFraction((double) 1 / (double) 2, 1.0e-5, 100));
123         customCustomAssertFraction(1, 3, new BigFraction((double) 1 / (double) 3, 1.0e-5, 100));
124         customCustomAssertFraction(2, 3, new BigFraction((double) 2 / (double) 3, 1.0e-5, 100));
125         customCustomAssertFraction(1, 4, new BigFraction((double) 1 / (double) 4, 1.0e-5, 100));
126         customCustomAssertFraction(3, 4, new BigFraction((double) 3 / (double) 4, 1.0e-5, 100));
127         customCustomAssertFraction(1, 5, new BigFraction((double) 1 / (double) 5, 1.0e-5, 100));
128         customCustomAssertFraction(2, 5, new BigFraction((double) 2 / (double) 5, 1.0e-5, 100));
129         customCustomAssertFraction(3, 5, new BigFraction((double) 3 / (double) 5, 1.0e-5, 100));
130         customCustomAssertFraction(4, 5, new BigFraction((double) 4 / (double) 5, 1.0e-5, 100));
131         customCustomAssertFraction(1, 6, new BigFraction((double) 1 / (double) 6, 1.0e-5, 100));
132         customCustomAssertFraction(5, 6, new BigFraction((double) 5 / (double) 6, 1.0e-5, 100));
133         customCustomAssertFraction(1, 7, new BigFraction((double) 1 / (double) 7, 1.0e-5, 100));
134         customCustomAssertFraction(2, 7, new BigFraction((double) 2 / (double) 7, 1.0e-5, 100));
135         customCustomAssertFraction(3, 7, new BigFraction((double) 3 / (double) 7, 1.0e-5, 100));
136         customCustomAssertFraction(4, 7, new BigFraction((double) 4 / (double) 7, 1.0e-5, 100));
137         customCustomAssertFraction(5, 7, new BigFraction((double) 5 / (double) 7, 1.0e-5, 100));
138         customCustomAssertFraction(6, 7, new BigFraction((double) 6 / (double) 7, 1.0e-5, 100));
139         customCustomAssertFraction(1, 8, new BigFraction((double) 1 / (double) 8, 1.0e-5, 100));
140         customCustomAssertFraction(3, 8, new BigFraction((double) 3 / (double) 8, 1.0e-5, 100));
141         customCustomAssertFraction(5, 8, new BigFraction((double) 5 / (double) 8, 1.0e-5, 100));
142         customCustomAssertFraction(7, 8, new BigFraction((double) 7 / (double) 8, 1.0e-5, 100));
143         customCustomAssertFraction(1, 9, new BigFraction((double) 1 / (double) 9, 1.0e-5, 100));
144         customCustomAssertFraction(2, 9, new BigFraction((double) 2 / (double) 9, 1.0e-5, 100));
145         customCustomAssertFraction(4, 9, new BigFraction((double) 4 / (double) 9, 1.0e-5, 100));
146         customCustomAssertFraction(5, 9, new BigFraction((double) 5 / (double) 9, 1.0e-5, 100));
147         customCustomAssertFraction(7, 9, new BigFraction((double) 7 / (double) 9, 1.0e-5, 100));
148         customCustomAssertFraction(8, 9, new BigFraction((double) 8 / (double) 9, 1.0e-5, 100));
149         customCustomAssertFraction(1, 10, new BigFraction((double) 1 / (double) 10, 1.0e-5, 100));
150         customCustomAssertFraction(3, 10, new BigFraction((double) 3 / (double) 10, 1.0e-5, 100));
151         customCustomAssertFraction(7, 10, new BigFraction((double) 7 / (double) 10, 1.0e-5, 100));
152         customCustomAssertFraction(9, 10, new BigFraction((double) 9 / (double) 10, 1.0e-5, 100));
153         customCustomAssertFraction(1, 11, new BigFraction((double) 1 / (double) 11, 1.0e-5, 100));
154         customCustomAssertFraction(2, 11, new BigFraction((double) 2 / (double) 11, 1.0e-5, 100));
155         customCustomAssertFraction(3, 11, new BigFraction((double) 3 / (double) 11, 1.0e-5, 100));
156         customCustomAssertFraction(4, 11, new BigFraction((double) 4 / (double) 11, 1.0e-5, 100));
157         customCustomAssertFraction(5, 11, new BigFraction((double) 5 / (double) 11, 1.0e-5, 100));
158         customCustomAssertFraction(6, 11, new BigFraction((double) 6 / (double) 11, 1.0e-5, 100));
159         customCustomAssertFraction(7, 11, new BigFraction((double) 7 / (double) 11, 1.0e-5, 100));
160         customCustomAssertFraction(8, 11, new BigFraction((double) 8 / (double) 11, 1.0e-5, 100));
161         customCustomAssertFraction(9, 11, new BigFraction((double) 9 / (double) 11, 1.0e-5, 100));
162         customCustomAssertFraction(10, 11, new BigFraction((double) 10 / (double) 11, 1.0e-5, 100));
163     }
164 
165     // MATH-181
166     @Test
167     void testDigitLimitConstructor() {
168         customCustomAssertFraction(2, 5, new BigFraction(0.4, 9));
169         customCustomAssertFraction(2, 5, new BigFraction(0.4, 99));
170         customCustomAssertFraction(2, 5, new BigFraction(0.4, 999));
171 
172         customCustomAssertFraction(3, 5, new BigFraction(0.6152, 9));
173         customCustomAssertFraction(8, 13, new BigFraction(0.6152, 99));
174         customCustomAssertFraction(510, 829, new BigFraction(0.6152, 999));
175         customCustomAssertFraction(769, 1250, new BigFraction(0.6152, 9999));
176 
177         // MATH-996
178         customCustomAssertFraction(1, 2, new BigFraction(0.5000000001, 10));
179     }
180 
181     // MATH-1029
182     @Test
183     void testPositiveValueOverflow() {
184         customCustomAssertFraction((long) 1e10, 1, new BigFraction(1e10, 1000));
185     }
186 
187     // MATH-1029
188     @Test
189     void testNegativeValueOverflow() {
190         customCustomAssertFraction((long) -1e10, 1, new BigFraction(-1e10, 1000));
191     }
192 
193     @Test
194     void testEpsilonLimitConstructor() {
195         customCustomAssertFraction(2, 5, new BigFraction(0.4, 1.0e-5, 100));
196 
197         customCustomAssertFraction(3, 5, new BigFraction(0.6152, 0.02, 100));
198         customCustomAssertFraction(8, 13, new BigFraction(0.6152, 1.0e-3, 100));
199         customCustomAssertFraction(251, 408, new BigFraction(0.6152, 1.0e-4, 100));
200         customCustomAssertFraction(251, 408, new BigFraction(0.6152, 1.0e-5, 100));
201         customCustomAssertFraction(510, 829, new BigFraction(0.6152, 1.0e-6, 100));
202         customCustomAssertFraction(769, 1250, new BigFraction(0.6152, 1.0e-7, 100));
203     }
204 
205     @Test
206     void testCompareTo() {
207         BigFraction first = new BigFraction(1, 2);
208         BigFraction second = new BigFraction(1, 3);
209         BigFraction third = new BigFraction(1, 2);
210 
211         assertEquals(0, first.compareTo(first));
212         assertEquals(0, first.compareTo(third));
213         assertEquals(1, first.compareTo(second));
214         assertEquals(-1, second.compareTo(first));
215 
216         // these two values are different approximations of PI
217         // the first  one is approximately PI - 3.07e-18
218         // the second one is approximately PI + 1.936e-17
219         BigFraction pi1 = new BigFraction(1068966896, 340262731);
220         BigFraction pi2 = new BigFraction( 411557987, 131002976);
221         assertEquals(-1, pi1.compareTo(pi2));
222         assertEquals( 1, pi2.compareTo(pi1));
223         assertEquals(0.0, pi1.doubleValue() - pi2.doubleValue(), 1.0e-20);
224 
225     }
226 
227     @Test
228     void testDoubleValue() {
229         BigFraction first = new BigFraction(1, 2);
230         BigFraction second = new BigFraction(1, 3);
231 
232         assertEquals(0.5, first.doubleValue(), 0.0);
233         assertEquals(1.0 / 3.0, second.doubleValue(), 0.0);
234     }
235 
236     // MATH-744
237     @Test
238     void testDoubleValueForLargeNumeratorAndDenominator() {
239         final BigInteger pow400 = BigInteger.TEN.pow(400);
240         final BigInteger pow401 = BigInteger.TEN.pow(401);
241         final BigInteger two = new BigInteger("2");
242         final BigFraction large = new BigFraction(pow401.add(BigInteger.ONE),
243                                                   pow400.multiply(two));
244 
245         assertEquals(5, large.doubleValue(), 1e-15);
246     }
247 
248     // MATH-744
249     @Test
250     void testFloatValueForLargeNumeratorAndDenominator() {
251         final BigInteger pow400 = BigInteger.TEN.pow(400);
252         final BigInteger pow401 = BigInteger.TEN.pow(401);
253         final BigInteger two = new BigInteger("2");
254         final BigFraction large = new BigFraction(pow401.add(BigInteger.ONE),
255                                                   pow400.multiply(two));
256 
257         assertEquals(5, large.floatValue(), 1e-15);
258     }
259 
260     @Test
261     void testFloatValue() {
262         BigFraction first = new BigFraction(1, 2);
263         BigFraction second = new BigFraction(1, 3);
264 
265         assertEquals(0.5f, first.floatValue(), 0.0f);
266         assertEquals((float) (1.0 / 3.0), second.floatValue(), 0.0f);
267     }
268 
269     @Test
270     void testIntValue() {
271         BigFraction first = new BigFraction(1, 2);
272         BigFraction second = new BigFraction(3, 2);
273 
274         assertEquals(0, first.intValue());
275         assertEquals(1, second.intValue());
276     }
277 
278     @Test
279     void testLongValue() {
280         BigFraction first = new BigFraction(1, 2);
281         BigFraction second = new BigFraction(3, 2);
282 
283         assertEquals(0L, first.longValue());
284         assertEquals(1L, second.longValue());
285     }
286 
287     @Test
288     void testConstructorDouble() {
289         customCustomAssertFraction(1, 2, new BigFraction(0.5));
290         customCustomAssertFraction(6004799503160661l, 18014398509481984l, new BigFraction(1.0 / 3.0));
291         customCustomAssertFraction(6124895493223875l, 36028797018963968l, new BigFraction(17.0 / 100.0));
292         customCustomAssertFraction(1784551352345559l, 562949953421312l, new BigFraction(317.0 / 100.0));
293         customCustomAssertFraction(-1, 2, new BigFraction(-0.5));
294         customCustomAssertFraction(-6004799503160661l, 18014398509481984l, new BigFraction(-1.0 / 3.0));
295         customCustomAssertFraction(-6124895493223875l, 36028797018963968l, new BigFraction(17.0 / -100.0));
296         customCustomAssertFraction(-1784551352345559l, 562949953421312l, new BigFraction(-317.0 / 100.0));
297         for (double v : new double[] { Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY}) {
298             try {
299                 new BigFraction(v);
300                 fail("Expecting MathIllegalArgumentException");
301             } catch (MathIllegalArgumentException iae) {
302                 // expected
303             }
304         }
305         assertEquals(1l, new BigFraction(Double.MAX_VALUE).getDenominatorAsLong());
306         assertEquals(1l, new BigFraction(Double.longBitsToDouble(0x0010000000000000L)).getNumeratorAsLong());
307         assertEquals(1l, new BigFraction(Double.MIN_VALUE).getNumeratorAsLong());
308     }
309 
310     @Test
311     void testAbs() {
312         BigFraction a = new BigFraction(10, 21);
313         BigFraction b = new BigFraction(-10, 21);
314         BigFraction c = new BigFraction(10, -21);
315 
316         customCustomAssertFraction(10, 21, a.abs());
317         customCustomAssertFraction(10, 21, b.abs());
318         customCustomAssertFraction(10, 21, c.abs());
319     }
320 
321     @Test
322     void testSignum() {
323         assertEquals(-1, new BigFraction(4, -5).signum());
324         assertEquals(-1, new BigFraction(-4, 5).signum());
325         assertEquals( 0, new BigFraction(0).signum());
326         assertEquals(+1, new BigFraction(-4, -5).signum());
327         assertEquals(+1, new BigFraction(4, 5).signum());
328     }
329 
330     @Test
331     void testReciprocal() {
332         BigFraction f = null;
333 
334         f = new BigFraction(50, 75);
335         f = f.reciprocal();
336         assertEquals(3, f.getNumeratorAsInt());
337         assertEquals(2, f.getDenominatorAsInt());
338 
339         f = new BigFraction(4, 3);
340         f = f.reciprocal();
341         assertEquals(3, f.getNumeratorAsInt());
342         assertEquals(4, f.getDenominatorAsInt());
343 
344         f = new BigFraction(-15, 47);
345         f = f.reciprocal();
346         assertEquals(-47, f.getNumeratorAsInt());
347         assertEquals(15, f.getDenominatorAsInt());
348 
349         f = new BigFraction(0, 3);
350         try {
351             f = f.reciprocal();
352             fail("expecting MathIllegalArgumentException");
353         } catch (MathIllegalArgumentException ex) {
354         }
355 
356         // large values
357         f = new BigFraction(Integer.MAX_VALUE, 1);
358         f = f.reciprocal();
359         assertEquals(1, f.getNumeratorAsInt());
360         assertEquals(Integer.MAX_VALUE, f.getDenominatorAsInt());
361     }
362 
363     @Test
364     void testNegate() {
365         BigFraction f = null;
366 
367         f = new BigFraction(50, 75);
368         f = f.negate();
369         assertEquals(-2, f.getNumeratorAsInt());
370         assertEquals(3, f.getDenominatorAsInt());
371 
372         f = new BigFraction(-50, 75);
373         f = f.negate();
374         assertEquals(2, f.getNumeratorAsInt());
375         assertEquals(3, f.getDenominatorAsInt());
376 
377         // large values
378         f = new BigFraction(Integer.MAX_VALUE - 1, Integer.MAX_VALUE);
379         f = f.negate();
380         assertEquals(Integer.MIN_VALUE + 2, f.getNumeratorAsInt());
381         assertEquals(Integer.MAX_VALUE, f.getDenominatorAsInt());
382 
383     }
384 
385     @Test
386     void testAdd() {
387         BigFraction a = new BigFraction(1, 2);
388         BigFraction b = new BigFraction(2, 3);
389 
390         customCustomAssertFraction(1, 1, a.add(a));
391         customCustomAssertFraction(7, 6, a.add(b));
392         customCustomAssertFraction(7, 6, b.add(a));
393         customCustomAssertFraction(4, 3, b.add(b));
394 
395         BigFraction f1 = new BigFraction(Integer.MAX_VALUE - 1, 1);
396         BigFraction f2 = BigFraction.ONE;
397         BigFraction f = f1.add(f2);
398         assertEquals(Integer.MAX_VALUE, f.getNumeratorAsInt());
399         assertEquals(1, f.getDenominatorAsInt());
400 
401         f1 = new BigFraction(-1, 13 * 13 * 2 * 2);
402         f2 = new BigFraction(-2, 13 * 17 * 2);
403         f = f1.add(f2);
404         assertEquals(13 * 13 * 17 * 2 * 2, f.getDenominatorAsInt());
405         assertEquals(-17 - 2 * 13 * 2, f.getNumeratorAsInt());
406 
407         try {
408             f.add((BigFraction) null);
409             fail("expecting NullArgumentException");
410         } catch (NullArgumentException ex) {
411         }
412 
413         // if this fraction is added naively, it will overflow.
414         // check that it doesn't.
415         f1 = new BigFraction(1, 32768 * 3);
416         f2 = new BigFraction(1, 59049);
417         f = f1.add(f2);
418         assertEquals(52451, f.getNumeratorAsInt());
419         assertEquals(1934917632, f.getDenominatorAsInt());
420 
421         f1 = new BigFraction(Integer.MIN_VALUE, 3);
422         f2 = new BigFraction(1, 3);
423         f = f1.add(f2);
424         assertEquals(Integer.MIN_VALUE + 1, f.getNumeratorAsInt());
425         assertEquals(3, f.getDenominatorAsInt());
426 
427         f1 = new BigFraction(Integer.MAX_VALUE - 1, 1);
428         f = f1.add(BigInteger.ONE);
429         assertEquals(Integer.MAX_VALUE, f.getNumeratorAsInt());
430         assertEquals(1, f.getDenominatorAsInt());
431 
432         f = f.add(BigInteger.ZERO);
433         assertEquals(Integer.MAX_VALUE, f.getNumeratorAsInt());
434         assertEquals(1, f.getDenominatorAsInt());
435 
436         f1 = new BigFraction(Integer.MAX_VALUE - 1, 1);
437         f = f1.add(1);
438         assertEquals(Integer.MAX_VALUE, f.getNumeratorAsInt());
439         assertEquals(1, f.getDenominatorAsInt());
440 
441         f = f.add(0);
442         assertEquals(Integer.MAX_VALUE, f.getNumeratorAsInt());
443         assertEquals(1, f.getDenominatorAsInt());
444 
445         f1 = new BigFraction(Integer.MAX_VALUE - 1, 1);
446         f = f1.add(1l);
447         assertEquals(Integer.MAX_VALUE, f.getNumeratorAsInt());
448         assertEquals(1, f.getDenominatorAsInt());
449 
450         f = f.add(0l);
451         assertEquals(Integer.MAX_VALUE, f.getNumeratorAsInt());
452         assertEquals(1, f.getDenominatorAsInt());
453 
454     }
455 
456     @Test
457     void testDivide() {
458         BigFraction a = new BigFraction(1, 2);
459         BigFraction b = new BigFraction(2, 3);
460 
461         customCustomAssertFraction(1, 1, a.divide(a));
462         customCustomAssertFraction(3, 4, a.divide(b));
463         customCustomAssertFraction(4, 3, b.divide(a));
464         customCustomAssertFraction(1, 1, b.divide(b));
465 
466         BigFraction f1 = new BigFraction(3, 5);
467         BigFraction f2 = BigFraction.ZERO;
468         try {
469             f1.divide(f2);
470             fail("expecting MathRuntimeException");
471         } catch (MathRuntimeException ex) {
472         }
473 
474         f1 = new BigFraction(0, 5);
475         f2 = new BigFraction(2, 7);
476         BigFraction f = f1.divide(f2);
477         assertSame(BigFraction.ZERO, f);
478 
479         f1 = new BigFraction(2, 7);
480         f2 = BigFraction.ONE;
481         f = f1.divide(f2);
482         assertEquals(2, f.getNumeratorAsInt());
483         assertEquals(7, f.getDenominatorAsInt());
484 
485         f1 = new BigFraction(1, Integer.MAX_VALUE);
486         f = f1.divide(f1);
487         assertEquals(1, f.getNumeratorAsInt());
488         assertEquals(1, f.getDenominatorAsInt());
489 
490         f1 = new BigFraction(Integer.MIN_VALUE, Integer.MAX_VALUE);
491         f2 = new BigFraction(1, Integer.MAX_VALUE);
492         f = f1.divide(f2);
493         assertEquals(Integer.MIN_VALUE, f.getNumeratorAsInt());
494         assertEquals(1, f.getDenominatorAsInt());
495 
496         try {
497             f.divide((BigFraction) null);
498             fail("expecting NullArgumentException");
499         } catch (NullArgumentException ex) {
500         }
501 
502         f1 = new BigFraction(Integer.MIN_VALUE, Integer.MAX_VALUE);
503         f = f1.divide(BigInteger.valueOf(Integer.MIN_VALUE));
504         assertEquals(Integer.MAX_VALUE, f.getDenominatorAsInt());
505         assertEquals(1, f.getNumeratorAsInt());
506 
507         f1 = new BigFraction(Integer.MIN_VALUE, Integer.MAX_VALUE);
508         f = f1.divide(Integer.MIN_VALUE);
509         assertEquals(Integer.MAX_VALUE, f.getDenominatorAsInt());
510         assertEquals(1, f.getNumeratorAsInt());
511 
512         f1 = new BigFraction(Integer.MIN_VALUE, Integer.MAX_VALUE);
513         f = f1.divide((long) Integer.MIN_VALUE);
514         assertEquals(Integer.MAX_VALUE, f.getDenominatorAsInt());
515         assertEquals(1, f.getNumeratorAsInt());
516 
517     }
518 
519     @Test
520     void testMultiply() {
521         BigFraction a = new BigFraction(1, 2);
522         BigFraction b = new BigFraction(2, 3);
523 
524         customCustomAssertFraction(1, 4, a.multiply(a));
525         customCustomAssertFraction(1, 3, a.multiply(b));
526         customCustomAssertFraction(1, 3, b.multiply(a));
527         customCustomAssertFraction(4, 9, b.multiply(b));
528 
529         BigFraction f1 = new BigFraction(Integer.MAX_VALUE, 1);
530         BigFraction f2 = new BigFraction(Integer.MIN_VALUE, Integer.MAX_VALUE);
531         BigFraction f = f1.multiply(f2);
532         assertEquals(Integer.MIN_VALUE, f.getNumeratorAsInt());
533         assertEquals(1, f.getDenominatorAsInt());
534 
535         f = f2.multiply(Integer.MAX_VALUE);
536         assertEquals(Integer.MIN_VALUE, f.getNumeratorAsInt());
537         assertEquals(1, f.getDenominatorAsInt());
538 
539         f = f2.multiply((long) Integer.MAX_VALUE);
540         assertEquals(Integer.MIN_VALUE, f.getNumeratorAsInt());
541         assertEquals(1, f.getDenominatorAsInt());
542 
543         try {
544             f.multiply((BigFraction) null);
545             fail("expecting NullArgumentException");
546         } catch (NullArgumentException ex) {
547         }
548 
549     }
550 
551     @Test
552     void testSubtract() {
553         BigFraction a = new BigFraction(1, 2);
554         BigFraction b = new BigFraction(2, 3);
555 
556         customCustomAssertFraction(0, 1, a.subtract(a));
557         customCustomAssertFraction(-1, 6, a.subtract(b));
558         customCustomAssertFraction(1, 6, b.subtract(a));
559         customCustomAssertFraction(0, 1, b.subtract(b));
560 
561         BigFraction f = new BigFraction(1, 1);
562         try {
563             f.subtract((BigFraction) null);
564             fail("expecting NullArgumentException");
565         } catch (NullArgumentException ex) {
566         }
567 
568         // if this fraction is subtracted naively, it will overflow.
569         // check that it doesn't.
570         BigFraction f1 = new BigFraction(1, 32768 * 3);
571         BigFraction f2 = new BigFraction(1, 59049);
572         f = f1.subtract(f2);
573         assertEquals(-13085, f.getNumeratorAsInt());
574         assertEquals(1934917632, f.getDenominatorAsInt());
575 
576         f1 = new BigFraction(Integer.MIN_VALUE, 3);
577         f2 = new BigFraction(1, 3).negate();
578         f = f1.subtract(f2);
579         assertEquals(Integer.MIN_VALUE + 1, f.getNumeratorAsInt());
580         assertEquals(3, f.getDenominatorAsInt());
581 
582         f1 = new BigFraction(Integer.MAX_VALUE, 1);
583         f2 = BigFraction.ONE;
584         f = f1.subtract(f2);
585         assertEquals(Integer.MAX_VALUE - 1, f.getNumeratorAsInt());
586         assertEquals(1, f.getDenominatorAsInt());
587 
588     }
589 
590     @Test
591     void testBigDecimalValue() {
592         assertEquals(new BigDecimal(0.5), new BigFraction(1, 2).bigDecimalValue());
593         assertEquals(new BigDecimal("0.0003"), new BigFraction(3, 10000).bigDecimalValue());
594         assertEquals(new BigDecimal("0"), new BigFraction(1, 3).bigDecimalValue(RoundingMode.DOWN));
595         assertEquals(new BigDecimal("0.333"), new BigFraction(1, 3).bigDecimalValue(3, RoundingMode.DOWN));
596     }
597 
598     @SuppressWarnings("unlikely-arg-type")
599     @Test
600     void testEqualsAndHashCode() {
601         BigFraction zero = new BigFraction(0, 1);
602         BigFraction nullFraction = null;
603         assertEquals(zero, zero);
604         assertNotEquals(zero, nullFraction);
605         assertNotEquals(zero, Double.valueOf(0));
606         BigFraction zero2 = new BigFraction(0, 2);
607         assertEquals(zero, zero2);
608         assertEquals(zero.hashCode(), zero2.hashCode());
609         BigFraction one = new BigFraction(1, 1);
610         assertFalse((one.equals(zero) || zero.equals(one)));
611         assertEquals(BigFraction.ONE, one);
612     }
613 
614     @Test
615     void testGCD() {
616       BigFraction first = new BigFraction(1, 3);
617       BigFraction second = new BigFraction(2, 5);
618       BigFraction third = new BigFraction(3, 7);
619       BigFraction gcd1 = first.gcd(second);
620         assertEquals(gcd1, BigFraction.getReducedFraction(1, 15));
621       BigFraction gcd2 = gcd1.gcd(third);
622         assertEquals(gcd2, BigFraction.getReducedFraction(1, 105));
623 
624       // example from https://math.stackexchange.com/a/151089
625       BigFraction x = new BigFraction(3, 7);
626       BigFraction y = new BigFraction(12, 22);
627       BigFraction gcd = x.gcd(y);
628         assertEquals(gcd, BigFraction.getReducedFraction(3, 77));
629 
630       x = new BigFraction(13, 6);
631       y = new BigFraction(3, 4);
632       gcd = x.gcd(y);
633         assertEquals(gcd, BigFraction.getReducedFraction(1, 12));
634 
635     }
636 
637     @Test
638     void testLCM() {
639       BigFraction first = new BigFraction(1, 3);
640       BigFraction second = new BigFraction(2, 5);
641       BigFraction third = new BigFraction(3, 7);
642       BigFraction lcm1 = first.lcm(second);
643         assertEquals(lcm1, BigFraction.getReducedFraction(2, 1));
644       BigFraction lcm2 = lcm1.lcm(third);
645         assertEquals(lcm2, BigFraction.getReducedFraction(6, 1));
646     }
647 
648     @Test
649     void testGetReducedFraction() {
650         BigFraction threeFourths = new BigFraction(3, 4);
651         assertEquals(threeFourths, BigFraction.getReducedFraction(6, 8));
652         assertEquals(BigFraction.ZERO, BigFraction.getReducedFraction(0, -1));
653         try {
654             BigFraction.getReducedFraction(1, 0);
655             fail("expecting MathIllegalArgumentException");
656         } catch (MathIllegalArgumentException ex) {
657             // expected
658         }
659         assertEquals(-1, BigFraction.getReducedFraction(2, Integer.MIN_VALUE).getNumeratorAsInt());
660         assertEquals(-1, BigFraction.getReducedFraction(1, -1).getNumeratorAsInt());
661     }
662 
663     @Test
664     void testPercentage() {
665         assertEquals(50.0, new BigFraction(1, 2).percentageValue(), 1.0e-15);
666     }
667 
668     @Test
669     void testPow() {
670         assertEquals(new BigFraction(8192, 1594323), new BigFraction(2, 3).pow(13));
671         assertEquals(new BigFraction(8192, 1594323), new BigFraction(2, 3).pow(13l));
672         assertEquals(new BigFraction(8192, 1594323), new BigFraction(2, 3).pow(BigInteger.valueOf(13l)));
673         assertEquals(BigFraction.ONE, new BigFraction(2, 3).pow(0));
674         assertEquals(BigFraction.ONE, new BigFraction(2, 3).pow(0l));
675         assertEquals(BigFraction.ONE, new BigFraction(2, 3).pow(BigInteger.valueOf(0l)));
676         assertEquals(new BigFraction(1594323, 8192), new BigFraction(2, 3).pow(-13));
677         assertEquals(new BigFraction(1594323, 8192), new BigFraction(2, 3).pow(-13l));
678         assertEquals(new BigFraction(1594323, 8192), new BigFraction(2, 3).pow(BigInteger.valueOf(-13l)));
679     }
680 
681     @Test
682     void testMath340() {
683         BigFraction fractionA = new BigFraction(0.00131);
684         BigFraction fractionB = new BigFraction(.37).reciprocal();
685         BigFraction errorResult = fractionA.multiply(fractionB);
686         BigFraction correctResult = new BigFraction(fractionA.getNumerator().multiply(fractionB.getNumerator()),
687                                                     fractionA.getDenominator().multiply(fractionB.getDenominator()));
688         assertEquals(correctResult, errorResult);
689     }
690 
691     @Test
692     void testNormalizedEquals() {
693         assertEquals(new BigFraction(237, -3871), new BigFraction(-51l, 833l));
694     }
695 
696     @Test
697     void testSerial() {
698         BigFraction[] fractions = {
699             new BigFraction(3, 4), BigFraction.ONE, BigFraction.ZERO,
700             new BigFraction(17), new BigFraction(FastMath.PI, 1000),
701             new BigFraction(-5, 2)
702         };
703         for (BigFraction fraction : fractions) {
704             assertEquals(fraction, UnitTestUtils.serializeAndRecover(fraction));
705         }
706     }
707 
708     @Test
709     void testConvergents() {
710         // OEIS A002485, Numerators of convergents to Pi (https://oeis.org/A002485)
711         // 0, 1, 3, 22, 333, 355, 103993, 104348, 208341, 312689, 833719, 1146408, 4272943, 5419351, 80143857, 165707065, 245850922
712         // OEIS A002486, Apart from two leading terms (which are present by convention), denominators of convergents to Pi (https://oeis.org/A002486)
713         // 1, 0, 1,  7, 106, 113,  33102,  33215,  66317,  99532, 265381,  364913, 1360120, 1725033, 25510582,  52746197, 78256779
714         List<BigFraction> convergents = BigFraction.convergents(FastMath.PI, 20).collect(Collectors.toList());
715         assertEquals(new BigFraction(       3,        1), convergents.get( 0));
716         assertEquals(new BigFraction(      22,        7), convergents.get( 1));
717         assertEquals(new BigFraction(     333,      106), convergents.get( 2));
718         assertEquals(new BigFraction(     355,      113), convergents.get( 3));
719         assertEquals(new BigFraction(  103993,    33102), convergents.get( 4));
720         assertEquals(new BigFraction(  104348,    33215), convergents.get( 5));
721         assertEquals(new BigFraction(  208341,    66317), convergents.get( 6));
722         assertEquals(new BigFraction(  312689,    99532), convergents.get( 7));
723         assertEquals(new BigFraction(  833719,   265381), convergents.get( 8));
724         assertEquals(new BigFraction( 1146408,   364913), convergents.get( 9));
725         assertEquals(new BigFraction( 4272943,  1360120), convergents.get(10));
726         assertEquals(new BigFraction( 5419351,  1725033), convergents.get(11));
727         assertEquals(new BigFraction(80143857, 25510582), convergents.get(12));
728         assertEquals(13, convergents.size());
729     }
730 
731     @Test
732     void testLimitedConvergents() {
733         double value = FastMath.PI;
734         assertEquals(new BigFraction(  208341,    66317),
735                 BigFraction.convergent(value, 7, (p, q) -> Precision.equals(p / (double) q, value, 1)).getKey());
736     }
737 
738     @Test
739     void testTruncatedConvergents() {
740         final double value = FastMath.PI;
741         assertEquals(new BigFraction(   355,   113),
742                 BigFraction.convergent(value, 20, (p, q) -> FastMath.abs(p / (double) q - value) < 1.0e-6).getKey());
743         assertEquals(new BigFraction(312689, 99532),
744                 BigFraction.convergent(value, 20, (p, q) -> FastMath.abs(p / (double) q - value) < 1.0e-10).getKey());
745     }
746 
747     @Test
748     void testOutOfRange() {
749         BigFraction f = new BigFraction(new BigInteger("1175443811202636889584648110261699215671929253339678037082566183036829784156100300341131818417591797406644569806405529752410539491566888996766640542430075310377605462098357361563685103574645710283612852841417362211504458393792053529953230572830415970785545248189857341548686469982966457542855773477057255734051"),
750                                         new BigInteger("32626522339992622633551470546282737778505821290344832738793182277348616222987431136114480634269341408071340993046760559082031250000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"));
751         // reference value compured using Emacs-calc with 20 digits
752         assertEquals(36.027247984128935385, f.doubleValue(), 1.0e-15);
753     }
754 
755 }