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 * http://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 package org.apache.commons.math.fraction;
18
19 import java.math.BigInteger;
20 import org.apache.commons.math.util.MathUtils;
21
22 /**
23 * Representation of a rational number.
24 *
25 * @since 1.1
26 * @version $Revision: 620373 $ $Date: 2008-02-10 18:18:39 -0700 (Sun, 10 Feb 2008) $
27 */
28 public class Fraction extends Number implements Comparable {
29
30 /** A fraction representing "1 / 1". */
31 public static final Fraction ONE = new Fraction(1, 1);
32
33 /** A fraction representing "0 / 1". */
34 public static final Fraction ZERO = new Fraction(0, 1);
35
36 /** Serializable version identifier */
37 private static final long serialVersionUID = -8958519416450949235L;
38
39 /** The denominator. */
40 private final int denominator;
41
42 /** The numerator. */
43 private final int numerator;
44
45 /**
46 * Create a fraction given the double value.
47 * @param value the double value to convert to a fraction.
48 * @throws FractionConversionException if the continued fraction failed to
49 * converge.
50 */
51 public Fraction(double value) throws FractionConversionException {
52 this(value, 1.0e-5, 100);
53 }
54
55 /**
56 * Create a fraction given the double value and maximum error allowed.
57 * <p>
58 * References:
59 * <ul>
60 * <li><a href="http://mathworld.wolfram.com/ContinuedFraction.html">
61 * Continued Fraction</a> equations (11) and (22)-(26)</li>
62 * </ul>
63 * </p>
64 * @param value the double value to convert to a fraction.
65 * @param epsilon maximum error allowed. The resulting fraction is within
66 * <code>epsilon</code> of <code>value</code>, in absolute terms.
67 * @param maxIterations maximum number of convergents
68 * @throws FractionConversionException if the continued fraction failed to
69 * converge.
70 */
71 public Fraction(double value, double epsilon, int maxIterations)
72 throws FractionConversionException
73 {
74 this(value, epsilon, Integer.MAX_VALUE, maxIterations);
75 }
76
77 /**
78 * Create a fraction given the double value and maximum denominator.
79 * <p>
80 * References:
81 * <ul>
82 * <li><a href="http://mathworld.wolfram.com/ContinuedFraction.html">
83 * Continued Fraction</a> equations (11) and (22)-(26)</li>
84 * </ul>
85 * </p>
86 * @param value the double value to convert to a fraction.
87 * @param maxDenominator The maximum allowed value for denominator
88 * @throws FractionConversionException if the continued fraction failed to
89 * converge
90 */
91 public Fraction(double value, int maxDenominator)
92 throws FractionConversionException
93 {
94 this(value, 0, maxDenominator, 100);
95 }
96
97 /**
98 * Create a fraction given the double value and either the maximum error
99 * allowed or the maximum number of denominator digits.
100 * <p>
101 *
102 * NOTE: This constructor is called with EITHER
103 * - a valid epsilon value and the maxDenominator set to Integer.MAX_VALUE
104 * (that way the maxDenominator has no effect).
105 * OR
106 * - a valid maxDenominator value and the epsilon value set to zero
107 * (that way epsilon only has effect if there is an exact match before
108 * the maxDenominator value is reached).
109 * </p><p>
110 *
111 * It has been done this way so that the same code can be (re)used for both
112 * scenarios. However this could be confusing to users if it were part of
113 * the public API and this constructor should therefore remain PRIVATE.
114 * </p>
115 *
116 * See JIRA issue ticket MATH-181 for more details:
117 *
118 * https://issues.apache.org/jira/browse/MATH-181
119 *
120 * @param value the double value to convert to a fraction.
121 * @param epsilon maximum error allowed. The resulting fraction is within
122 * <code>epsilon</code> of <code>value</code>, in absolute terms.
123 * @param maxDenominator maximum denominator value allowed.
124 * @param maxIterations maximum number of convergents
125 * @throws FractionConversionException if the continued fraction failed to
126 * converge.
127 */
128 private Fraction(double value, double epsilon, int maxDenominator, int maxIterations)
129 throws FractionConversionException
130 {
131 long overflow = Integer.MAX_VALUE;
132 double r0 = value;
133 long a0 = (long)Math.floor(r0);
134 if (a0 > overflow) {
135 throw new FractionConversionException(value, a0, 1l);
136 }
137
138 // check for (almost) integer arguments, which should not go
139 // to iterations.
140 if (Math.abs(a0 - value) < epsilon) {
141 this.numerator = (int) a0;
142 this.denominator = 1;
143 return;
144 }
145
146 long p0 = 1;
147 long q0 = 0;
148 long p1 = a0;
149 long q1 = 1;
150
151 long p2 = 0;
152 long q2 = 1;
153
154 int n = 0;
155 boolean stop = false;
156 do {
157 ++n;
158 double r1 = 1.0 / (r0 - a0);
159 long a1 = (long)Math.floor(r1);
160 p2 = (a1 * p1) + p0;
161 q2 = (a1 * q1) + q0;
162 if ((p2 > overflow) || (q2 > overflow)) {
163 throw new FractionConversionException(value, p2, q2);
164 }
165
166 double convergent = (double)p2 / (double)q2;
167 if (n < maxIterations && Math.abs(convergent - value) > epsilon && q2 < maxDenominator) {
168 p0 = p1;
169 p1 = p2;
170 q0 = q1;
171 q1 = q2;
172 a0 = a1;
173 r0 = r1;
174 } else {
175 stop = true;
176 }
177 } while (!stop);
178
179 if (n >= maxIterations) {
180 throw new FractionConversionException(value, maxIterations);
181 }
182
183 if (q2 < maxDenominator) {
184 this.numerator = (int) p2;
185 this.denominator = (int) q2;
186 } else {
187 this.numerator = (int) p1;
188 this.denominator = (int) q1;
189 }
190
191 }
192
193 /**
194 * Create a fraction given the numerator and denominator. The fraction is
195 * reduced to lowest terms.
196 * @param num the numerator.
197 * @param den the denominator.
198 * @throws ArithmeticException if the denomiator is <code>zero</code>
199 */
200 public Fraction(int num, int den) {
201 super();
202 if (den == 0) {
203 throw new ArithmeticException("The denominator must not be zero");
204 }
205 if (den < 0) {
206 if (num == Integer.MIN_VALUE ||
207 den == Integer.MIN_VALUE) {
208 throw new ArithmeticException("overflow: can't negate");
209 }
210 num = -num;
211 den = -den;
212 }
213 // reduce numerator and denominator by greatest common denominator.
214 int d = MathUtils.gcd(num, den);
215 if (d > 1) {
216 num /= d;
217 den /= d;
218 }
219
220 // move sign to numerator.
221 if (den < 0) {
222 num *= -1;
223 den *= -1;
224 }
225 this.numerator = num;
226 this.denominator = den;
227 }
228
229 /**
230 * Returns the absolute value of this fraction.
231 * @return the absolute value.
232 */
233 public Fraction abs() {
234 Fraction ret;
235 if (numerator >= 0) {
236 ret = this;
237 } else {
238 ret = negate();
239 }
240 return ret;
241 }
242
243 /**
244 * Compares this object to another based on size.
245 * @param object the object to compare to
246 * @return -1 if this is less than <tt>object</tt>, +1 if this is greater
247 * than <tt>object</tt>, 0 if they are equal.
248 */
249 public int compareTo(Object object) {
250 int ret = 0;
251
252 if (this != object) {
253 Fraction other = (Fraction)object;
254 double first = doubleValue();
255 double second = other.doubleValue();
256
257 if (first < second) {
258 ret = -1;
259 } else if (first > second) {
260 ret = 1;
261 }
262 }
263
264 return ret;
265 }
266
267 /**
268 * Gets the fraction as a <tt>double</tt>. This calculates the fraction as
269 * the numerator divided by denominator.
270 * @return the fraction as a <tt>double</tt>
271 */
272 public double doubleValue() {
273 return (double)numerator / (double)denominator;
274 }
275
276 /**
277 * Test for the equality of two fractions. If the lowest term
278 * numerator and denominators are the same for both fractions, the two
279 * fractions are considered to be equal.
280 * @param other fraction to test for equality to this fraction
281 * @return true if two fractions are equal, false if object is
282 * <tt>null</tt>, not an instance of {@link Fraction}, or not equal
283 * to this fraction instance.
284 */
285 public boolean equals(Object other) {
286 boolean ret;
287
288 if (this == other) {
289 ret = true;
290 } else if (other == null) {
291 ret = false;
292 } else {
293 try {
294 // since fractions are always in lowest terms, numerators and
295 // denominators can be compared directly for equality.
296 Fraction rhs = (Fraction)other;
297 ret = (numerator == rhs.numerator) &&
298 (denominator == rhs.denominator);
299 } catch (ClassCastException ex) {
300 // ignore exception
301 ret = false;
302 }
303 }
304
305 return ret;
306 }
307
308 /**
309 * Gets the fraction as a <tt>float</tt>. This calculates the fraction as
310 * the numerator divided by denominator.
311 * @return the fraction as a <tt>float</tt>
312 */
313 public float floatValue() {
314 return (float)doubleValue();
315 }
316
317 /**
318 * Access the denominator.
319 * @return the denominator.
320 */
321 public int getDenominator() {
322 return denominator;
323 }
324
325 /**
326 * Access the numerator.
327 * @return the numerator.
328 */
329 public int getNumerator() {
330 return numerator;
331 }
332
333 /**
334 * Gets a hashCode for the fraction.
335 * @return a hash code value for this object
336 */
337 public int hashCode() {
338 return 37 * (37 * 17 + getNumerator()) + getDenominator();
339 }
340
341 /**
342 * Gets the fraction as an <tt>int</tt>. This returns the whole number part
343 * of the fraction.
344 * @return the whole number fraction part
345 */
346 public int intValue() {
347 return (int)doubleValue();
348 }
349
350 /**
351 * Gets the fraction as a <tt>long</tt>. This returns the whole number part
352 * of the fraction.
353 * @return the whole number fraction part
354 */
355 public long longValue() {
356 return (long)doubleValue();
357 }
358
359 /**
360 * Return the additive inverse of this fraction.
361 * @return the negation of this fraction.
362 */
363 public Fraction negate() {
364 if (numerator==Integer.MIN_VALUE) {
365 throw new ArithmeticException("overflow: too large to negate");
366 }
367 return new Fraction(-numerator, denominator);
368 }
369
370 /**
371 * Return the multiplicative inverse of this fraction.
372 * @return the reciprocal fraction
373 */
374 public Fraction reciprocal() {
375 return new Fraction(denominator, numerator);
376 }
377
378 /**
379 * <p>Adds the value of this fraction to another, returning the result in reduced form.
380 * The algorithm follows Knuth, 4.5.1.</p>
381 *
382 * @param fraction the fraction to add, must not be <code>null</code>
383 * @return a <code>Fraction</code> instance with the resulting values
384 * @throws IllegalArgumentException if the fraction is <code>null</code>
385 * @throws ArithmeticException if the resulting numerator or denominator exceeds
386 * <code>Integer.MAX_VALUE</code>
387 */
388 public Fraction add(Fraction fraction) {
389 return addSub(fraction, true /* add */);
390 }
391
392 /**
393 * <p>Subtracts the value of another fraction from the value of this one,
394 * returning the result in reduced form.</p>
395 *
396 * @param fraction the fraction to subtract, must not be <code>null</code>
397 * @return a <code>Fraction</code> instance with the resulting values
398 * @throws IllegalArgumentException if the fraction is <code>null</code>
399 * @throws ArithmeticException if the resulting numerator or denominator
400 * cannot be represented in an <code>int</code>.
401 */
402 public Fraction subtract(Fraction fraction) {
403 return addSub(fraction, false /* subtract */);
404 }
405
406 /**
407 * Implement add and subtract using algorithm described in Knuth 4.5.1.
408 *
409 * @param fraction the fraction to subtract, must not be <code>null</code>
410 * @param isAdd true to add, false to subtract
411 * @return a <code>Fraction</code> instance with the resulting values
412 * @throws IllegalArgumentException if the fraction is <code>null</code>
413 * @throws ArithmeticException if the resulting numerator or denominator
414 * cannot be represented in an <code>int</code>.
415 */
416 private Fraction addSub(Fraction fraction, boolean isAdd) {
417 if (fraction == null) {
418 throw new IllegalArgumentException("The fraction must not be null");
419 }
420 // zero is identity for addition.
421 if (numerator == 0) {
422 return isAdd ? fraction : fraction.negate();
423 }
424 if (fraction.numerator == 0) {
425 return this;
426 }
427 // if denominators are randomly distributed, d1 will be 1 about 61%
428 // of the time.
429 int d1 = MathUtils.gcd(denominator, fraction.denominator);
430 if (d1==1) {
431 // result is ( (u*v' +/- u'v) / u'v')
432 int uvp = MathUtils.mulAndCheck(numerator, fraction.denominator);
433 int upv = MathUtils.mulAndCheck(fraction.numerator, denominator);
434 return new Fraction
435 (isAdd ? MathUtils.addAndCheck(uvp, upv) :
436 MathUtils.subAndCheck(uvp, upv),
437 MathUtils.mulAndCheck(denominator, fraction.denominator));
438 }
439 // the quantity 't' requires 65 bits of precision; see knuth 4.5.1
440 // exercise 7. we're going to use a BigInteger.
441 // t = u(v'/d1) +/- v(u'/d1)
442 BigInteger uvp = BigInteger.valueOf(numerator)
443 .multiply(BigInteger.valueOf(fraction.denominator/d1));
444 BigInteger upv = BigInteger.valueOf(fraction.numerator)
445 .multiply(BigInteger.valueOf(denominator/d1));
446 BigInteger t = isAdd ? uvp.add(upv) : uvp.subtract(upv);
447 // but d2 doesn't need extra precision because
448 // d2 = gcd(t,d1) = gcd(t mod d1, d1)
449 int tmodd1 = t.mod(BigInteger.valueOf(d1)).intValue();
450 int d2 = (tmodd1==0)?d1:MathUtils.gcd(tmodd1, d1);
451
452 // result is (t/d2) / (u'/d1)(v'/d2)
453 BigInteger w = t.divide(BigInteger.valueOf(d2));
454 if (w.bitLength() > 31) {
455 throw new ArithmeticException
456 ("overflow: numerator too large after multiply");
457 }
458 return new Fraction (w.intValue(),
459 MathUtils.mulAndCheck(denominator/d1,
460 fraction.denominator/d2));
461 }
462
463 /**
464 * <p>Multiplies the value of this fraction by another, returning the
465 * result in reduced form.</p>
466 *
467 * @param fraction the fraction to multiply by, must not be <code>null</code>
468 * @return a <code>Fraction</code> instance with the resulting values
469 * @throws IllegalArgumentException if the fraction is <code>null</code>
470 * @throws ArithmeticException if the resulting numerator or denominator exceeds
471 * <code>Integer.MAX_VALUE</code>
472 */
473 public Fraction multiply(Fraction fraction) {
474 if (fraction == null) {
475 throw new IllegalArgumentException("The fraction must not be null");
476 }
477 if (numerator == 0 || fraction.numerator == 0) {
478 return ZERO;
479 }
480 // knuth 4.5.1
481 // make sure we don't overflow unless the result *must* overflow.
482 int d1 = MathUtils.gcd(numerator, fraction.denominator);
483 int d2 = MathUtils.gcd(fraction.numerator, denominator);
484 return getReducedFraction
485 (MathUtils.mulAndCheck(numerator/d1, fraction.numerator/d2),
486 MathUtils.mulAndCheck(denominator/d2, fraction.denominator/d1));
487 }
488
489 /**
490 * <p>Divide the value of this fraction by another.</p>
491 *
492 * @param fraction the fraction to divide by, must not be <code>null</code>
493 * @return a <code>Fraction</code> instance with the resulting values
494 * @throws IllegalArgumentException if the fraction is <code>null</code>
495 * @throws ArithmeticException if the fraction to divide by is zero
496 * @throws ArithmeticException if the resulting numerator or denominator exceeds
497 * <code>Integer.MAX_VALUE</code>
498 */
499 public Fraction divide(Fraction fraction) {
500 if (fraction == null) {
501 throw new IllegalArgumentException("The fraction must not be null");
502 }
503 if (fraction.numerator == 0) {
504 throw new ArithmeticException("The fraction to divide by must not be zero");
505 }
506 return multiply(fraction.reciprocal());
507 }
508
509 /**
510 * <p>Creates a <code>Fraction</code> instance with the 2 parts
511 * of a fraction Y/Z.</p>
512 *
513 * <p>Any negative signs are resolved to be on the numerator.</p>
514 *
515 * @param numerator the numerator, for example the three in 'three sevenths'
516 * @param denominator the denominator, for example the seven in 'three sevenths'
517 * @return a new fraction instance, with the numerator and denominator reduced
518 * @throws ArithmeticException if the denominator is <code>zero</code>
519 */
520 public static Fraction getReducedFraction(int numerator, int denominator) {
521 if (denominator == 0) {
522 throw new ArithmeticException("The denominator must not be zero");
523 }
524 if (numerator==0) {
525 return ZERO; // normalize zero.
526 }
527 // allow 2^k/-2^31 as a valid fraction (where k>0)
528 if (denominator==Integer.MIN_VALUE && (numerator&1)==0) {
529 numerator/=2; denominator/=2;
530 }
531 if (denominator < 0) {
532 if (numerator==Integer.MIN_VALUE ||
533 denominator==Integer.MIN_VALUE) {
534 throw new ArithmeticException("overflow: can't negate");
535 }
536 numerator = -numerator;
537 denominator = -denominator;
538 }
539 // simplify fraction.
540 int gcd = MathUtils.gcd(numerator, denominator);
541 numerator /= gcd;
542 denominator /= gcd;
543 return new Fraction(numerator, denominator);
544 }
545 }