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 package org.apache.commons.lang3.math;
18
19 import java.io.IOException;
20 import java.io.InvalidObjectException;
21 import java.io.ObjectInputStream;
22 import java.io.Serializable;
23 import java.math.BigInteger;
24 import java.util.Objects;
25
26 /**
27 * {@link Fraction} is a {@link Number} implementation that stores fractions accurately.
28 * <p>
29 * This class is immutable, and interoperable with most methods that accept a {@link Number}.
30 * </p>
31 * <p>
32 * Note that this class is intended for common use cases, it is <em>int</em> based and thus suffers from various overflow issues. For a BigInteger based
33 * equivalent, please see the Commons Math BigFraction class.
34 * </p>
35 *
36 * @since 2.0
37 */
38 public final class Fraction extends Number implements Comparable<Fraction> {
39
40 /**
41 * Required for serialization support. Lang version 2.0.
42 *
43 * @see Serializable
44 */
45 private static final long serialVersionUID = 65382027393090L;
46
47 /**
48 * {@link Fraction} representation of 0.
49 */
50 public static final Fraction ZERO = new Fraction(0, 1);
51
52 /**
53 * {@link Fraction} representation of 1.
54 */
55 public static final Fraction ONE = new Fraction(1, 1);
56
57 /**
58 * {@link Fraction} representation of 1/2.
59 */
60 public static final Fraction ONE_HALF = new Fraction(1, 2);
61
62 /**
63 * {@link Fraction} representation of 1/3.
64 */
65 public static final Fraction ONE_THIRD = new Fraction(1, 3);
66
67 /**
68 * {@link Fraction} representation of 2/3.
69 */
70 public static final Fraction TWO_THIRDS = new Fraction(2, 3);
71
72 /**
73 * {@link Fraction} representation of 1/4.
74 */
75 public static final Fraction ONE_QUARTER = new Fraction(1, 4);
76
77 /**
78 * {@link Fraction} representation of 2/4.
79 */
80 public static final Fraction TWO_QUARTERS = new Fraction(2, 4);
81
82 /**
83 * {@link Fraction} representation of 3/4.
84 */
85 public static final Fraction THREE_QUARTERS = new Fraction(3, 4);
86
87 /**
88 * {@link Fraction} representation of 1/5.
89 */
90 public static final Fraction ONE_FIFTH = new Fraction(1, 5);
91
92 /**
93 * {@link Fraction} representation of 2/5.
94 */
95 public static final Fraction TWO_FIFTHS = new Fraction(2, 5);
96
97 /**
98 * {@link Fraction} representation of 3/5.
99 */
100 public static final Fraction THREE_FIFTHS = new Fraction(3, 5);
101
102 /**
103 * {@link Fraction} representation of 4/5.
104 */
105 public static final Fraction FOUR_FIFTHS = new Fraction(4, 5);
106
107 /**
108 * Checks that a denominator is not zero.
109 *
110 * @param denominator The denominator to check
111 * @throws ArithmeticException Thrown if the denominator is zero.
112 */
113 private static void checkDenominator(final int denominator) {
114 if (denominator == 0) {
115 throw new ArithmeticException("The denominator must not be zero");
116 }
117 }
118
119 /**
120 * Gets a {@link Fraction} instance from a {@code double} value.
121 * <p>
122 * This method uses the <a href="https://web.archive.org/web/20210516065058/http%3A//archives.math.utk.edu/articles/atuyl/confrac/"> continued fraction
123 * algorithm</a>, computing a maximum of 25 convergents and bounding the denominator by 10,000.
124 * </p>
125 *
126 * @param value The double value to convert
127 * @return A new fraction instance that is close to the value
128 * @throws ArithmeticException Thrown if {@code |value| > Integer.MAX_VALUE} or {@code value = NaN}.
129 * @throws ArithmeticException Thrown if the calculated denominator is {@code zero}.
130 * @throws ArithmeticException Thrown if the algorithm does not converge.
131 */
132 public static Fraction getFraction(double value) {
133 final int sign = value < 0 ? -1 : 1;
134 value = Math.abs(value);
135 if (value > Integer.MAX_VALUE || Double.isNaN(value)) {
136 throw new ArithmeticException("The value must not be greater than Integer.MAX_VALUE or NaN");
137 }
138 final int wholeNumber = (int) value;
139 value -= wholeNumber;
140 int numer0 = 0; // the pre-previous
141 int denom0 = 1; // the pre-previous
142 int numer1 = 1; // the previous
143 int denom1 = 0; // the previous
144 int numer2; // the current, setup in calculation
145 int denom2; // the current, setup in calculation
146 int a1 = (int) value;
147 int a2;
148 double x1 = 1;
149 double x2;
150 double y1 = value - a1;
151 double y2;
152 double delta1;
153 double delta2 = Double.MAX_VALUE;
154 double fraction;
155 int i = 1;
156 do {
157 delta1 = delta2;
158 a2 = (int) (x1 / y1);
159 x2 = y1;
160 y2 = x1 - a2 * y1;
161 numer2 = a1 * numer1 + numer0;
162 denom2 = a1 * denom1 + denom0;
163 fraction = (double) numer2 / (double) denom2;
164 delta2 = Math.abs(value - fraction);
165 a1 = a2;
166 x1 = x2;
167 y1 = y2;
168 numer0 = numer1;
169 denom0 = denom1;
170 numer1 = numer2;
171 denom1 = denom2;
172 i++;
173 } while (delta1 > delta2 && denom2 <= 10000 && denom2 > 0 && i < 25);
174 if (i == 25) {
175 throw new ArithmeticException("Unable to convert double to fraction");
176 }
177 // wholeNumber can be up to Integer.MAX_VALUE while denom0 > 1 for any non-integer value,
178 // so the int product overflows for values near the limit; check it instead of wrapping silently.
179 final int numerator = Math.addExact(numer0, mulAndCheck(wholeNumber, denom0));
180 return getReducedFraction(numerator * sign, denom0);
181 }
182
183 /**
184 * Gets a {@link Fraction} instance with the 2 parts of a fraction Y/Z.
185 * <p>
186 * Any negative signs are resolved to be on the numerator.
187 * </p>
188 *
189 * @param numerator The numerator, for example the three in 'three sevenths'
190 * @param denominator The denominator, for example the seven in 'three sevenths'
191 * @return A new fraction instance
192 * @throws ArithmeticException Thrown if the denominator is {@code zero} or the denominator is {@code negative} and the numerator is
193 * {@code Integer#MIN_VALUE}.
194 */
195 public static Fraction getFraction(int numerator, int denominator) {
196 checkDenominator(denominator);
197 if (denominator < 0) {
198 if (numerator == Integer.MIN_VALUE || denominator == Integer.MIN_VALUE) {
199 throw new ArithmeticException("overflow: can't negate");
200 }
201 numerator = -numerator;
202 denominator = -denominator;
203 }
204 return new Fraction(numerator, denominator);
205 }
206
207 /**
208 * Gets a {@link Fraction} instance with the 3 parts of a fraction X Y/Z.
209 * <p>
210 * The negative sign must be passed in on the whole number part.
211 * </p>
212 *
213 * @param whole The whole number, for example the one in 'one and three sevenths'
214 * @param numerator The numerator, for example the three in 'one and three sevenths'
215 * @param denominator The denominator, for example the seven in 'one and three sevenths'
216 * @return A new fraction instance
217 * @throws ArithmeticException Thrown if the denominator is {@code zero}.
218 * @throws ArithmeticException Thrown if the denominator is negative.
219 * @throws ArithmeticException Thrown if the numerator is negative.
220 * @throws ArithmeticException Thrown if the resulting numerator exceeds {@code Integer.MAX_VALUE}.
221 */
222 public static Fraction getFraction(final int whole, final int numerator, final int denominator) {
223 checkDenominator(denominator);
224 if (denominator < 0) {
225 throw new ArithmeticException("The denominator must not be negative");
226 }
227 if (numerator < 0) {
228 throw new ArithmeticException("The numerator must not be negative");
229 }
230 final long numeratorValue;
231 if (whole < 0) {
232 numeratorValue = whole * (long) denominator - numerator;
233 } else {
234 numeratorValue = whole * (long) denominator + numerator;
235 }
236 if (numeratorValue < Integer.MIN_VALUE || numeratorValue > Integer.MAX_VALUE) {
237 throw new ArithmeticException("Numerator too large to represent as an Integer.");
238 }
239 return new Fraction((int) numeratorValue, denominator);
240 }
241
242 /**
243 * Gets a Fraction from a {@link String}.
244 * <p>
245 * The formats accepted are:
246 * </p>
247 * <ol>
248 * <li>{@code double} String containing a dot</li>
249 * <li>{@code "X Y/Z"}</li>
250 * <li>{@code "Y/Z"}</li>
251 * <li>{@code "X"} (a simple whole number)</li>
252 * </ol>
253 * <p>
254 * and a {@code .}
255 * </p>
256 *
257 * @param str The string to parse, must not be {@code null}
258 * @return The new {@link Fraction} instance
259 * @throws NullPointerException Thrown if the string is {@code null}
260 * @throws NumberFormatException Thrown if the number format is invalid, or if the string is well-formed but its value cannot be represented as a
261 * {@code Fraction}: a zero denominator such as {@code "1/0"}, a value outside the range of an {@code int} such as
262 * {@code "9999999999.5"}, or a mixed number whose combined numerator overflows. For those unrepresentable values, the causal
263 * {@link ArithmeticException} is preserved as the {@link Throwable#getCause() cause}.
264 */
265 public static Fraction getFraction(final String str) {
266 Objects.requireNonNull(str, "str");
267 // parse double format
268 int pos = str.indexOf('.');
269 if (pos >= 0) {
270 final double value = Double.parseDouble(str);
271 try {
272 return getFraction(value);
273 } catch (final ArithmeticException e) {
274 throw toNumberFormatException(str, e);
275 }
276 }
277
278 // parse X Y/Z format
279 pos = str.indexOf(' ');
280 if (pos > 0) {
281 final int whole = Integer.parseInt(str.substring(0, pos));
282 final String remainder = str.substring(pos + 1);
283 pos = remainder.indexOf('/');
284 if (pos < 0) {
285 throw new NumberFormatException("The fraction could not be parsed as the format X Y/Z");
286 }
287 final int numer = Integer.parseInt(remainder.substring(0, pos));
288 final int denom = Integer.parseInt(remainder.substring(pos + 1));
289 try {
290 return getFraction(whole, numer, denom);
291 } catch (final ArithmeticException e) {
292 throw toNumberFormatException(str, e);
293 }
294 }
295
296 // parse Y/Z format
297 pos = str.indexOf('/');
298 if (pos < 0) {
299 // simple whole number
300 return getFraction(Integer.parseInt(str), 1);
301 }
302 final int numer = Integer.parseInt(str.substring(0, pos));
303 final int denom = Integer.parseInt(str.substring(pos + 1));
304 try {
305 return getFraction(numer, denom);
306 } catch (final ArithmeticException e) {
307 throw toNumberFormatException(str, e);
308 }
309 }
310
311 /**
312 * Gets a reduced {@link Fraction} instance with the 2 parts of a fraction Y/Z.
313 * <p>
314 * For example, if the input parameters represent 2/4, then the created fraction will be 1/2.
315 * </p>
316 *
317 * <p>
318 * Any negative signs are resolved to be on the numerator.
319 * </p>
320 *
321 * @param numerator The numerator, for example the three in 'three sevenths'
322 * @param denominator The denominator, for example the seven in 'three sevenths'
323 * @return A new fraction instance, with the numerator and denominator reduced
324 * @throws ArithmeticException Thrown if the denominator is {@code zero}, or the reduced numerator or positive denominator cannot be represented as an
325 * {@code int}.
326 */
327 public static Fraction getReducedFraction(int numerator, int denominator) {
328 checkDenominator(denominator);
329 if (numerator == 0) {
330 return ZERO; // normalize zero.
331 }
332 // Reduce common powers of two before sign normalization to avoid negating Integer.MIN_VALUE.
333 while ((numerator & 1) == 0 && (denominator & 1) == 0) {
334 numerator /= 2;
335 denominator /= 2;
336 }
337 if (denominator < 0) {
338 if (numerator == Integer.MIN_VALUE || denominator == Integer.MIN_VALUE) {
339 throw new ArithmeticException("overflow: can't negate");
340 }
341 numerator = -numerator;
342 denominator = -denominator;
343 }
344 // simplify fraction.
345 final int gcd = greatestCommonDivisor(numerator, denominator);
346 numerator /= gcd;
347 denominator /= gcd;
348 return new Fraction(numerator, denominator);
349 }
350
351 /**
352 * Gets the greatest common divisor of the absolute value of
353 * two numbers, using the "binary gcd" method which avoids
354 * division and modulo operations. See Knuth 4.5.2 algorithm B.
355 * This algorithm is due to Josef Stein (1961).
356 *
357 * @param u A non-zero number
358 * @param v A non-zero number
359 * @return The greatest common divisor, never zero
360 */
361 private static int greatestCommonDivisor(int u, int v) {
362 // From Commons Math:
363 if (u == 0 || v == 0) {
364 if (u == Integer.MIN_VALUE || v == Integer.MIN_VALUE) {
365 throw new ArithmeticException("overflow: gcd is 2^31");
366 }
367 return Math.abs(u) + Math.abs(v);
368 }
369 // if either operand is abs 1, return 1:
370 if (Math.abs(u) == 1 || Math.abs(v) == 1) {
371 return 1;
372 }
373 // keep u and v negative, as negative integers range down to
374 // -2^31, while positive numbers can only be as large as 2^31-1
375 // (i.e. we can't necessarily negate a negative number without
376 // overflow)
377 if (u > 0) {
378 u = -u;
379 } // make u negative
380 if (v > 0) {
381 v = -v;
382 } // make v negative
383 // B1. [Find power of 2]
384 int k = 0;
385 while ((u & 1) == 0 && (v & 1) == 0 && k < 31) { // while u and v are both even...
386 u /= 2;
387 v /= 2;
388 k++; // cast out twos.
389 }
390 if (k == 31) {
391 throw new ArithmeticException("overflow: gcd is 2^31");
392 }
393 // B2. Initialize: u and v have been divided by 2^k and at least
394 // one is odd.
395 int t = (u & 1) == 1 ? v : -(u / 2)/* B3 */;
396 // t negative: u was odd, v may be even (t replaces v)
397 // t positive: u was even, v is odd (t replaces u)
398 do {
399 /* assert u<0 && v<0; */
400 // B4/B3: cast out twos from t.
401 while ((t & 1) == 0) { // while t is even.
402 t /= 2; // cast out twos
403 }
404 // B5 [reset max(u,v)]
405 if (t > 0) {
406 u = -t;
407 } else {
408 v = t;
409 }
410 // B6/B3. at this point both u and v should be odd.
411 t = (v - u) / 2;
412 // |u| larger: t positive (replace u)
413 // |v| larger: t negative (replace v)
414 } while (t != 0);
415 return -u * (1 << k); // gcd is u*2^k
416 }
417
418 private static int hash(final int value1, final int value2) {
419 return Objects.hash(value1, value2);
420 }
421
422 /**
423 * Multiplies two integers, checking for overflow.
424 *
425 * @param x A factor
426 * @param y A factor
427 * @return The product {@code x*y}
428 * @throws ArithmeticException Thrown if the result cannot be represented as an int.
429 */
430 private static int mulAndCheck(final int x, final int y) {
431 final long m = (long) x * (long) y;
432 if (m < Integer.MIN_VALUE || m > Integer.MAX_VALUE) {
433 throw new ArithmeticException("overflow: mul");
434 }
435 return (int) m;
436 }
437
438 /**
439 * Multiplies two non-negative integers, checking for overflow.
440 *
441 * @param x A non-negative factor
442 * @param y A non-negative factor
443 * @return The product {@code x*y}
444 * @throws ArithmeticException Thrown if the result cannot be represented as an int.
445 */
446 private static int mulPosAndCheck(final int x, final int y) {
447 /* assert x>=0 && y>=0; */
448 final long m = (long) x * (long) y;
449 if (m > Integer.MAX_VALUE) {
450 throw new ArithmeticException("overflow: mulPos");
451 }
452 return (int) m;
453 }
454
455 /**
456 * Converts an {@link ArithmeticException} raised while parsing a string into the {@link NumberFormatException} that
457 * {@link #getFraction(String)} documents, preserving the original exception as the cause.
458 *
459 * @param str The string being parsed.
460 * @param cause The arithmetic failure: a zero denominator or a value outside the range of an {@code int}.
461 * @return The exception for the caller to throw, never {@code null}.
462 */
463 private static NumberFormatException toNumberFormatException(final String str, final ArithmeticException cause) {
464 final NumberFormatException nfe = new NumberFormatException("The fraction could not be parsed from '" + str + "': " + cause.getMessage());
465 nfe.initCause(cause);
466 return nfe;
467 }
468
469 /**
470 * The numerator number part of the fraction (the three in three sevenths).
471 */
472 private final int numerator;
473
474 /**
475 * The denominator number part of the fraction (the seven in three sevenths).
476 */
477 private final int denominator;
478
479 /**
480 * Cached output hashCode (class is immutable).
481 */
482 private final int hashCode;
483
484 /**
485 * Cached output toString (class is immutable).
486 */
487 private transient String toString;
488
489 /**
490 * Cached output toProperString (class is immutable).
491 */
492 private transient String toProperString;
493
494 /**
495 * Constructs a {@link Fraction} instance with the 2 parts
496 * of a fraction Y/Z.
497 *
498 * @param numerator The numerator, for example the three in 'three sevenths'
499 * @param denominator The denominator, for example the seven in 'three sevenths'
500 */
501 private Fraction(final int numerator, final int denominator) {
502 this.numerator = numerator;
503 this.denominator = denominator;
504 this.hashCode = hash(denominator, numerator);
505 }
506
507 /**
508 * Gets a fraction that is the positive equivalent of this one.
509 * <p>
510 * More precisely: {@code (fraction >= 0 ? this : -fraction)}
511 * </p>
512 * <p>
513 * The returned fraction is not reduced.
514 * </p>
515 *
516 * @return {@code this} if it is positive, or a new positive fraction instance with the opposite signed numerator
517 */
518 public Fraction abs() {
519 if (numerator >= 0) {
520 return this;
521 }
522 return negate();
523 }
524
525 /**
526 * Adds the value of this fraction to another, returning the result in reduced form.
527 * The algorithm follows Knuth, 4.5.1.
528 *
529 * @param fraction The fraction to add, must not be {@code null}
530 * @return A {@link Fraction} instance with the resulting values
531 * @throws NullPointerException Thrown if the fraction is {@code null}.
532 * @throws ArithmeticException Thrown if the resulting numerator or denominator exceeds {@code Integer.MAX_VALUE}.
533 */
534 public Fraction add(final Fraction fraction) {
535 return addSub(fraction, true /* add */);
536 }
537
538 /**
539 * Implements add and subtract using the algorithm described in <a href="https://www-cs-faculty.stanford.edu/~knuth/taocp.html">
540 * The Art of Computer Programming (TAOCP)</a> 4.5.1 by Donald Knuth.
541 *
542 * @param fraction The fraction to subtract, must not be {@code null}
543 * @param isAdd true to add, false to subtract
544 * @return A {@link Fraction} instance with the resulting values
545 * @throws IllegalArgumentException Thrown if the fraction is {@code null}.
546 * @throws ArithmeticException Thrown if the resulting numerator or denominator
547 * cannot be represented in an {@code int}.
548 */
549 private Fraction addSub(final Fraction fraction, final boolean isAdd) {
550 Objects.requireNonNull(fraction, "fraction");
551 // zero is identity for addition.
552 if (numerator == 0) {
553 return isAdd ? fraction.reduce() : fraction.reduce().negate();
554 }
555 if (fraction.numerator == 0) {
556 return reduce();
557 }
558 // Knuth 4.5.1 assumes operands in lowest terms and this class does not reduce on
559 // construction, so reduce both first, as multiplyBy does.
560 final int thisGcd = greatestCommonDivisor(numerator, denominator);
561 final int thatGcd = greatestCommonDivisor(fraction.numerator, fraction.denominator);
562 final int thisNumerator = numerator / thisGcd;
563 final int thisDenominator = denominator / thisGcd;
564 final int thatNumerator = fraction.numerator / thatGcd;
565 final int thatDenominator = fraction.denominator / thatGcd;
566 // if denominators are randomly distributed, d1 will be 1 about 61%
567 // of the time.
568 final int d1 = greatestCommonDivisor(thisDenominator, thatDenominator);
569 if (d1 == 1) {
570 // result is ((u*v' +/- u'v) / u'v')
571 // the int cross products u*v' and u'*v can overflow even when the reduced result
572 // fits an int, so widen to long and let Math narrow the final numerator back.
573 final long uvp = (long) thisNumerator * thatDenominator;
574 final long upv = (long) thatNumerator * thisDenominator;
575 final long t = isAdd ? Math.addExact(uvp, upv) : Math.subtractExact(uvp, upv);
576 return new Fraction(Math.toIntExact(t), mulPosAndCheck(thisDenominator, thatDenominator));
577 }
578 // the quantity 't' requires 65 bits of precision; see knuth 4.5.1
579 // exercise 7. we're going to use a BigInteger.
580 // t = u(v'/d1) +/- v(u'/d1)
581 final BigInteger uvp = BigInteger.valueOf(thisNumerator).multiply(BigInteger.valueOf(thatDenominator / d1));
582 final BigInteger upv = BigInteger.valueOf(thatNumerator).multiply(BigInteger.valueOf(thisDenominator / d1));
583 final BigInteger t = isAdd ? uvp.add(upv) : uvp.subtract(upv);
584 // but d2 doesn't need extra precision because
585 // d2 = gcd(t,d1) = gcd(t mod d1, d1)
586 final int tmodd1 = t.mod(BigInteger.valueOf(d1)).intValue();
587 final int d2 = tmodd1 == 0 ? d1 : greatestCommonDivisor(tmodd1, d1);
588
589 // result is (t/d2) / (u'/d1)(v'/d2)
590 final BigInteger w = t.divide(BigInteger.valueOf(d2));
591 if (w.bitLength() > 31) {
592 throw new ArithmeticException("overflow: numerator too large after multiply");
593 }
594 return new Fraction(w.intValue(), mulPosAndCheck(thisDenominator / d1, thatDenominator / d2));
595 }
596
597 /**
598 * Compares this object to another based on size.
599 * <p>
600 * Note: this class has a natural ordering that is inconsistent with equals, because, for example, equals treats 1/2 and 2/4 as different, whereas compareTo
601 * treats them as equal.
602 * </p>
603 *
604 * @param other The object to compare to
605 * @return -1 if this is less, 0 if equal, +1 if greater
606 * @throws ClassCastException Thrown if the object is not a {@link Fraction}.
607 * @throws NullPointerException Thrown if the object is {@code null}.
608 */
609 @Override
610 public int compareTo(final Fraction other) {
611 if (this == other || numerator == other.numerator && denominator == other.denominator) {
612 return 0;
613 }
614
615 // otherwise see which is less
616 final long first = (long) numerator * (long) other.denominator;
617 final long second = (long) other.numerator * (long) denominator;
618 return Long.compare(first, second);
619 }
620
621 /**
622 * Divide the value of this fraction by another.
623 *
624 * @param fraction The fraction to divide by, must not be {@code null}
625 * @return A {@link Fraction} instance with the resulting values
626 * @throws NullPointerException Thrown if the fraction is {@code null}.
627 * @throws ArithmeticException Thrown if the fraction to divide by is zero.
628 * @throws ArithmeticException Thrown if the resulting numerator or denominator exceeds {@code Integer.MAX_VALUE}.
629 */
630 public Fraction divideBy(final Fraction fraction) {
631 Objects.requireNonNull(fraction, "fraction");
632 if (fraction.numerator == 0) {
633 throw new ArithmeticException("The fraction to divide by must not be zero");
634 }
635 return multiplyBy(fraction.invert());
636 }
637
638 /**
639 * Gets the fraction as a {@code double}. This calculates the fraction
640 * as the numerator divided by denominator.
641 *
642 * @return The fraction as a {@code double}
643 */
644 @Override
645 public double doubleValue() {
646 return (double) numerator / (double) denominator;
647 }
648
649 /**
650 * Compares this fraction to another object to test if they are equal.
651 * <p>
652 * To be equal, both values must be equal. Thus 2/4 is not equal to 1/2.
653 * </p>
654 *
655 * @param obj The reference object with which to compare
656 * @return {@code true} if this object is equal
657 */
658 @Override
659 public boolean equals(final Object obj) {
660 if (obj == this) {
661 return true;
662 }
663 if (!(obj instanceof Fraction)) {
664 return false;
665 }
666 final Fraction other = (Fraction) obj;
667 return getNumerator() == other.getNumerator() && getDenominator() == other.getDenominator();
668 }
669
670 /**
671 * Gets the fraction as a {@code float}. This calculates the fraction
672 * as the numerator divided by denominator.
673 *
674 * @return The fraction as a {@code float}
675 */
676 @Override
677 public float floatValue() {
678 return (float) numerator / (float) denominator;
679 }
680
681 /**
682 * Gets the denominator part of the fraction.
683 *
684 * @return The denominator fraction part
685 */
686 public int getDenominator() {
687 return denominator;
688 }
689
690 /**
691 * Gets the numerator part of the fraction.
692 * <p>
693 * This method may return a value greater than the denominator, an improper fraction, such as the seven in 7/4.
694 * </p>
695 *
696 * @return The numerator fraction part
697 */
698 public int getNumerator() {
699 return numerator;
700 }
701
702 /**
703 * Gets the proper numerator, always positive.
704 * <p>
705 * An improper fraction 7/4 can be resolved into a proper one, 1 3/4. This method returns the 3 from the proper fraction.
706 * </p>
707 *
708 * <p>
709 * If the fraction is negative such as -7/4, it can be resolved into -1 3/4, so this method returns the positive proper numerator, 3.
710 * </p>
711 *
712 * @return The numerator fraction part of a proper fraction, always positive
713 */
714 public int getProperNumerator() {
715 return Math.abs(numerator % denominator);
716 }
717
718 /**
719 * Gets the proper whole part of the fraction.
720 * <p>
721 * An improper fraction 7/4 can be resolved into a proper one, 1 3/4. This method returns the 1 from the proper fraction.
722 * </p>
723 *
724 * <p>
725 * If the fraction is negative such as -7/4, it can be resolved into -1 3/4, so this method returns the positive whole part -1.
726 * </p>
727 *
728 * @return The whole fraction part of a proper fraction, that includes the sign
729 */
730 public int getProperWhole() {
731 return numerator / denominator;
732 }
733
734 /**
735 * Gets a hashCode for the fraction.
736 *
737 * @return A hash code value for this object
738 */
739 @Override
740 public int hashCode() {
741 return hashCode;
742 }
743
744 /**
745 * Gets the fraction as an {@code int}. This returns the whole number
746 * part of the fraction.
747 *
748 * @return The whole number fraction part
749 */
750 @Override
751 public int intValue() {
752 return numerator / denominator;
753 }
754
755 /**
756 * Gets a fraction that is the inverse (1/fraction) of this one.
757 * <p>
758 * The returned fraction is not reduced.
759 * </p>
760 *
761 * @return A new fraction instance with the numerator and denominator inverted.
762 * @throws ArithmeticException Thrown if the fraction represents zero.
763 */
764 public Fraction invert() {
765 if (numerator == 0) {
766 throw new ArithmeticException("Unable to invert zero.");
767 }
768 if (numerator == Integer.MIN_VALUE) {
769 throw new ArithmeticException("overflow: can't negate numerator");
770 }
771 if (numerator < 0) {
772 return new Fraction(-denominator, -numerator);
773 }
774 return new Fraction(denominator, numerator);
775 }
776
777 /**
778 * Gets the fraction as a {@code long}. This returns the whole number
779 * part of the fraction.
780 *
781 * @return The whole number fraction part
782 */
783 @Override
784 public long longValue() {
785 return (long) numerator / denominator;
786 }
787
788 /**
789 * Multiplies the value of this fraction by another, returning the
790 * result in reduced form.
791 *
792 * @param fraction The fraction to multiply by, must not be {@code null}
793 * @return A {@link Fraction} instance with the resulting values
794 * @throws NullPointerException Thrown if the fraction is {@code null}.
795 * @throws ArithmeticException Thrown if the resulting numerator or denominator exceeds {@code Integer.MAX_VALUE}.
796 */
797 public Fraction multiplyBy(final Fraction fraction) {
798 Objects.requireNonNull(fraction, "fraction");
799 if (numerator == 0 || fraction.numerator == 0) {
800 return ZERO;
801 }
802 // knuth 4.5.1
803 // make sure we don't overflow unless the result *must* overflow.
804 // Reduce both operands first: the cross-gcd below cancels the cross terms only, so a
805 // factor shared inside an unreduced operand survives into the product and can overflow
806 // an int even when the reduced result fits.
807 final int thisGcd = greatestCommonDivisor(numerator, denominator);
808 final int thatGcd = greatestCommonDivisor(fraction.numerator, fraction.denominator);
809 final int thisNumerator = numerator / thisGcd;
810 final int thisDenominator = denominator / thisGcd;
811 final int thatNumerator = fraction.numerator / thatGcd;
812 final int thatDenominator = fraction.denominator / thatGcd;
813 final int d1 = greatestCommonDivisor(thisNumerator, thatDenominator);
814 final int d2 = greatestCommonDivisor(thatNumerator, thisDenominator);
815 return getReducedFraction(mulAndCheck(thisNumerator / d1, thatNumerator / d2), mulPosAndCheck(thisDenominator / d2, thatDenominator / d1));
816 }
817
818 /**
819 * Gets a fraction that is the negative (-fraction) of this one.
820 * <p>
821 * The returned fraction is not reduced.
822 * </p>
823 *
824 * @return A new fraction instance with the opposite signed numerator
825 */
826 public Fraction negate() {
827 // the positive range is one smaller than the negative range of an int.
828 if (numerator == Integer.MIN_VALUE) {
829 throw new ArithmeticException("overflow: too large to negate");
830 }
831 return new Fraction(-numerator, denominator);
832 }
833
834 /**
835 * Gets a fraction that is raised to the passed in power.
836 * <p>
837 * The returned fraction is in reduced form.
838 * </p>
839 *
840 * @param power The power to raise the fraction to
841 * @return {@code this} if the power is one, {@link #ONE} if the power is zero (even if the fraction equals ZERO) or a new fraction instance raised to the
842 * appropriate power
843 * @throws ArithmeticException Thrown if the resulting numerator or denominator exceeds {@code Integer.MAX_VALUE}.
844 */
845 public Fraction pow(final int power) {
846 if (power == 1) {
847 return this;
848 }
849 if (power == 0) {
850 return ONE;
851 }
852 if (power < 0) {
853 if (power == Integer.MIN_VALUE) { // MIN_VALUE can't be negated.
854 return invert().pow(2).pow(-(power / 2));
855 }
856 return invert().pow(-power);
857 }
858 final Fraction f = multiplyBy(this);
859 if (power % 2 == 0) { // if even...
860 return f.pow(power / 2);
861 }
862 return f.pow(power / 2).multiplyBy(this);
863 }
864
865 /**
866 * Validates the cached hashCode after deserialization. Throws a {@link InvalidObjectException} when the stored hashCode does not match the canonical hash
867 * of the deserialized numerator/denominator.
868 *
869 * @param in See {@link Serializable}.
870 * @throws IOException Thrown as described in {@link Serializable}.
871 * @throws ClassNotFoundException Thrown as described in {@link Serializable}.
872 * @throws InvalidObjectException Thrown if the hashCode doesn't match the denominator and numerator.
873 */
874 private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
875 in.defaultReadObject();
876 checkDenominator(denominator);
877 if (hashCode != hash(denominator, numerator)) {
878 throw new InvalidObjectException("Fraction hashCode does not match numerator/denominator.");
879 }
880 }
881
882 /**
883 * Reduce the fraction to the smallest values for the numerator and denominator, returning the result.
884 * <p>
885 * For example, if this fraction represents 2/4, then the result will be 1/2.
886 * </p>
887 *
888 * @return A new reduced fraction instance, or this if no simplification possible
889 */
890 public Fraction reduce() {
891 if (numerator == 0) {
892 return equals(ZERO) ? this : ZERO;
893 }
894 final int gcd = greatestCommonDivisor(Math.abs(numerator), denominator);
895 if (gcd == 1) {
896 return this;
897 }
898 return getFraction(numerator / gcd, denominator / gcd);
899 }
900
901 /**
902 * Subtracts the value of another fraction from the value of this one,
903 * returning the result in reduced form.
904 *
905 * @param fraction The fraction to subtract, must not be {@code null}
906 * @return A {@link Fraction} instance with the resulting values
907 * @throws NullPointerException Thrown if the fraction is {@code null}.
908 * @throws ArithmeticException Thrown if the resulting numerator or denominator
909 * cannot be represented in an {@code int}.
910 */
911 public Fraction subtract(final Fraction fraction) {
912 return addSub(fraction, false /* subtract */);
913 }
914
915 /**
916 * Gets the fraction as a proper {@link String} in the format X Y/Z.
917 * <p>
918 * The format used in '<em>wholeNumber</em> <em>numerator</em>/<em>denominator</em>'. If the whole number is zero it will be omitted. If the numerator is
919 * zero, only the whole number is returned.
920 * </p>
921 *
922 * @return A {@link String} form of the fraction
923 */
924 public String toProperString() {
925 if (toProperString == null) {
926 if (numerator == 0) {
927 toProperString = "0";
928 } else if (numerator == denominator) {
929 toProperString = "1";
930 } else if (numerator == -1 * denominator) {
931 toProperString = "-1";
932 } else if ((numerator > 0 ? -numerator : numerator) < -denominator) {
933 // note that we do the magnitude comparison test above with
934 // NEGATIVE (not positive) numbers, since negative numbers
935 // have a larger range. otherwise numerator == Integer.MIN_VALUE
936 // is handled incorrectly.
937 final int properNumerator = getProperNumerator();
938 if (properNumerator == 0) {
939 toProperString = Integer.toString(getProperWhole());
940 } else {
941 toProperString = getProperWhole() + " " + properNumerator + "/" + getDenominator();
942 }
943 } else {
944 toProperString = getNumerator() + "/" + getDenominator();
945 }
946 }
947 return toProperString;
948 }
949
950 /**
951 * Gets the fraction as a {@link String}.
952 * <p>
953 * The format used is '<em>numerator</em>/<em>denominator</em>' always.
954 * </p>
955 *
956 * @return A {@link String} form of the fraction
957 */
958 @Override
959 public String toString() {
960 if (toString == null) {
961 toString = getNumerator() + "/" + getDenominator();
962 }
963 return toString;
964 }
965 }