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