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