• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package android.util;
17 
18 import static com.android.internal.util.Preconditions.*;
19 
20 import java.io.IOException;
21 import java.io.InvalidObjectException;
22 
23 /**
24  * <p>An immutable data type representation a rational number.</p>
25  *
26  * <p>Contains a pair of {@code int}s representing the numerator and denominator of a
27  * Rational number. </p>
28  */
29 public final class Rational extends Number implements Comparable<Rational> {
30     /**
31      * Constant for the <em>Not-a-Number (NaN)</em> value of the {@code Rational} type.
32      *
33      * <p>A {@code NaN} value is considered to be equal to itself (that is {@code NaN.equals(NaN)}
34      * will return {@code true}; it is always greater than any non-{@code NaN} value (that is
35      * {@code NaN.compareTo(notNaN)} will return a number greater than {@code 0}).</p>
36      *
37      * <p>Equivalent to constructing a new rational with both the numerator and denominator
38      * equal to {@code 0}.</p>
39      */
40     public static final Rational NaN = new Rational(0, 0);
41 
42     /**
43      * Constant for the positive infinity value of the {@code Rational} type.
44      *
45      * <p>Equivalent to constructing a new rational with a positive numerator and a denominator
46      * equal to {@code 0}.</p>
47      */
48     public static final Rational POSITIVE_INFINITY = new Rational(1, 0);
49 
50     /**
51      * Constant for the negative infinity value of the {@code Rational} type.
52      *
53      * <p>Equivalent to constructing a new rational with a negative numerator and a denominator
54      * equal to {@code 0}.</p>
55      */
56     public static final Rational NEGATIVE_INFINITY = new Rational(-1, 0);
57 
58     /**
59      * Constant for the zero value of the {@code Rational} type.
60      *
61      * <p>Equivalent to constructing a new rational with a numerator equal to {@code 0} and
62      * any non-zero denominator.</p>
63      */
64     public static final Rational ZERO = new Rational(0, 1);
65 
66     /**
67      * Unique version number per class to be compliant with {@link java.io.Serializable}.
68      *
69      * <p>Increment each time the fields change in any way.</p>
70      */
71     private static final long serialVersionUID = 1L;
72 
73     /*
74      * Do not change the order of these fields or add new instance fields to maintain the
75      * Serializable compatibility across API revisions.
76      */
77     private final int mNumerator;
78     private final int mDenominator;
79 
80     /**
81      * <p>Create a {@code Rational} with a given numerator and denominator.</p>
82      *
83      * <p>The signs of the numerator and the denominator may be flipped such that the denominator
84      * is always positive. Both the numerator and denominator will be converted to their reduced
85      * forms (see {@link #equals} for more details).</p>
86      *
87      * <p>For example,
88      * <ul>
89      * <li>a rational of {@code 2/4} will be reduced to {@code 1/2}.
90      * <li>a rational of {@code 1/-1} will be flipped to {@code -1/1}
91      * <li>a rational of {@code 5/0} will be reduced to {@code 1/0}
92      * <li>a rational of {@code 0/5} will be reduced to {@code 0/1}
93      * </ul>
94      * </p>
95      *
96      * @param numerator the numerator of the rational
97      * @param denominator the denominator of the rational
98      *
99      * @see #equals
100      */
Rational(int numerator, int denominator)101     public Rational(int numerator, int denominator) {
102 
103         if (denominator < 0) {
104             numerator = -numerator;
105             denominator = -denominator;
106         }
107 
108         // Convert to reduced form
109         if (denominator == 0 && numerator > 0) {
110             mNumerator = 1; // +Inf
111             mDenominator = 0;
112         } else if (denominator == 0 && numerator < 0) {
113             mNumerator = -1; // -Inf
114             mDenominator = 0;
115         } else if (denominator == 0 && numerator == 0) {
116             mNumerator = 0; // NaN
117             mDenominator = 0;
118         } else if (numerator == 0) {
119             mNumerator = 0;
120             mDenominator = 1;
121         } else {
122             int gcd = gcd(numerator, denominator);
123 
124             mNumerator = numerator / gcd;
125             mDenominator = denominator / gcd;
126         }
127     }
128 
129     /**
130      * Gets the numerator of the rational.
131      *
132      * <p>The numerator will always return {@code 1} if this rational represents
133      * infinity (that is, the denominator is {@code 0}).</p>
134      */
getNumerator()135     public int getNumerator() {
136         return mNumerator;
137     }
138 
139     /**
140      * Gets the denominator of the rational
141      *
142      * <p>The denominator may return {@code 0}, in which case the rational may represent
143      * positive infinity (if the numerator was positive), negative infinity (if the numerator
144      * was negative), or {@code NaN} (if the numerator was {@code 0}).</p>
145      *
146      * <p>The denominator will always return {@code 1} if the numerator is {@code 0}.
147      */
getDenominator()148     public int getDenominator() {
149         return mDenominator;
150     }
151 
152     /**
153      * Indicates whether this rational is a <em>Not-a-Number (NaN)</em> value.
154      *
155      * <p>A {@code NaN} value occurs when both the numerator and the denominator are {@code 0}.</p>
156      *
157      * @return {@code true} if this rational is a <em>Not-a-Number (NaN)</em> value;
158      *         {@code false} if this is a (potentially infinite) number value
159      */
isNaN()160     public boolean isNaN() {
161         return mDenominator == 0 && mNumerator == 0;
162     }
163 
164     /**
165      * Indicates whether this rational represents an infinite value.
166      *
167      * <p>An infinite value occurs when the denominator is {@code 0} (but the numerator is not).</p>
168      *
169      * @return {@code true} if this rational is a (positive or negative) infinite value;
170      *         {@code false} if this is a finite number value (or {@code NaN})
171      */
isInfinite()172     public boolean isInfinite() {
173         return mNumerator != 0 && mDenominator == 0;
174     }
175 
176     /**
177      * Indicates whether this rational represents a finite value.
178      *
179      * <p>A finite value occurs when the denominator is not {@code 0}; in other words
180      * the rational is neither infinity or {@code NaN}.</p>
181      *
182      * @return {@code true} if this rational is a (positive or negative) infinite value;
183      *         {@code false} if this is a finite number value (or {@code NaN})
184      */
isFinite()185     public boolean isFinite() {
186         return mDenominator != 0;
187     }
188 
189     /**
190      * Indicates whether this rational represents a zero value.
191      *
192      * <p>A zero value is a {@link #isFinite finite} rational with a numerator of {@code 0}.</p>
193      *
194      * @return {@code true} if this rational is finite zero value;
195      *         {@code false} otherwise
196      */
isZero()197     public boolean isZero() {
198         return isFinite() && mNumerator == 0;
199     }
200 
isPosInf()201     private boolean isPosInf() {
202         return mDenominator == 0 && mNumerator > 0;
203     }
204 
isNegInf()205     private boolean isNegInf() {
206         return mDenominator == 0 && mNumerator < 0;
207     }
208 
209     /**
210      * <p>Compare this Rational to another object and see if they are equal.</p>
211      *
212      * <p>A Rational object can only be equal to another Rational object (comparing against any
213      * other type will return {@code false}).</p>
214      *
215      * <p>A Rational object is considered equal to another Rational object if and only if one of
216      * the following holds:</p>
217      * <ul><li>Both are {@code NaN}</li>
218      *     <li>Both are infinities of the same sign</li>
219      *     <li>Both have the same numerator and denominator in their reduced form</li>
220      * </ul>
221      *
222      * <p>A reduced form of a Rational is calculated by dividing both the numerator and the
223      * denominator by their greatest common divisor.</p>
224      *
225      * <pre>{@code
226      * (new Rational(1, 2)).equals(new Rational(1, 2)) == true   // trivially true
227      * (new Rational(2, 3)).equals(new Rational(1, 2)) == false  // trivially false
228      * (new Rational(1, 2)).equals(new Rational(2, 4)) == true   // true after reduction
229      * (new Rational(0, 0)).equals(new Rational(0, 0)) == true   // NaN.equals(NaN)
230      * (new Rational(1, 0)).equals(new Rational(5, 0)) == true   // both are +infinity
231      * (new Rational(1, 0)).equals(new Rational(-1, 0)) == false // +infinity != -infinity
232      * }</pre>
233      *
234      * @param obj a reference to another object
235      *
236      * @return A boolean that determines whether or not the two Rational objects are equal.
237      */
238     @Override
equals(Object obj)239     public boolean equals(Object obj) {
240         return obj instanceof Rational && equals((Rational) obj);
241     }
242 
equals(Rational other)243     private boolean equals(Rational other) {
244         return (mNumerator == other.mNumerator && mDenominator == other.mDenominator);
245     }
246 
247     /**
248      * Return a string representation of this rational, e.g. {@code "1/2"}.
249      *
250      * <p>The following rules of conversion apply:
251      * <ul>
252      * <li>{@code NaN} values will return {@code "NaN"}
253      * <li>Positive infinity values will return {@code "Infinity"}
254      * <li>Negative infinity values will return {@code "-Infinity"}
255      * <li>All other values will return {@code "numerator/denominator"} where {@code numerator}
256      * and {@code denominator} are substituted with the appropriate numerator and denominator
257      * values.
258      * </ul></p>
259      */
260     @Override
toString()261     public String toString() {
262         if (isNaN()) {
263             return "NaN";
264         } else if (isPosInf()) {
265             return "Infinity";
266         } else if (isNegInf()) {
267             return "-Infinity";
268         } else {
269             return mNumerator + "/" + mDenominator;
270         }
271     }
272 
273     /**
274      * <p>Convert to a floating point representation.</p>
275      *
276      * @return The floating point representation of this rational number.
277      * @hide
278      */
toFloat()279     public float toFloat() {
280         // TODO: remove this duplicate function (used in CTS and the shim)
281         return floatValue();
282     }
283 
284     /**
285      * {@inheritDoc}
286      */
287     @Override
hashCode()288     public int hashCode() {
289         // Bias the hash code for the first (2^16) values for both numerator and denominator
290         int numeratorFlipped = mNumerator << 16 | mNumerator >>> 16;
291 
292         return mDenominator ^ numeratorFlipped;
293     }
294 
295     /**
296      * Calculates the greatest common divisor using Euclid's algorithm.
297      *
298      * <p><em>Visible for testing only.</em></p>
299      *
300      * @param numerator the numerator in a fraction
301      * @param denominator the denominator in a fraction
302      *
303      * @return An int value representing the gcd. Always positive.
304      * @hide
305      */
gcd(int numerator, int denominator)306     public static int gcd(int numerator, int denominator) {
307         /*
308          * Non-recursive implementation of Euclid's algorithm:
309          *
310          *  gcd(a, 0) := a
311          *  gcd(a, b) := gcd(b, a mod b)
312          *
313          */
314         int a = numerator;
315         int b = denominator;
316 
317         while (b != 0) {
318             int oldB = b;
319 
320             b = a % b;
321             a = oldB;
322         }
323 
324         return Math.abs(a);
325     }
326 
327     /**
328      * Returns the value of the specified number as a {@code double}.
329      *
330      * <p>The {@code double} is calculated by converting both the numerator and denominator
331      * to a {@code double}; then returning the result of dividing the numerator by the
332      * denominator.</p>
333      *
334      * @return the divided value of the numerator and denominator as a {@code double}.
335      */
336     @Override
doubleValue()337     public double doubleValue() {
338         double num = mNumerator;
339         double den = mDenominator;
340 
341         return num / den;
342     }
343 
344     /**
345      * Returns the value of the specified number as a {@code float}.
346      *
347      * <p>The {@code float} is calculated by converting both the numerator and denominator
348      * to a {@code float}; then returning the result of dividing the numerator by the
349      * denominator.</p>
350      *
351      * @return the divided value of the numerator and denominator as a {@code float}.
352      */
353     @Override
floatValue()354     public float floatValue() {
355         float num = mNumerator;
356         float den = mDenominator;
357 
358         return num / den;
359     }
360 
361     /**
362      * Returns the value of the specified number as a {@code int}.
363      *
364      * <p>{@link #isInfinite Finite} rationals are converted to an {@code int} value
365      * by dividing the numerator by the denominator; conversion for non-finite values happens
366      * identically to casting a floating point value to an {@code int}, in particular:
367      *
368      * <p>
369      * <ul>
370      * <li>Positive infinity saturates to the largest maximum integer
371      * {@link Integer#MAX_VALUE}</li>
372      * <li>Negative infinity saturates to the smallest maximum integer
373      * {@link Integer#MIN_VALUE}</li>
374      * <li><em>Not-A-Number (NaN)</em> returns {@code 0}.</li>
375      * </ul>
376      * </p>
377      *
378      * @return the divided value of the numerator and denominator as a {@code int}.
379      */
380     @Override
intValue()381     public int intValue() {
382         // Mimic float to int conversion rules from JLS 5.1.3
383 
384         if (isPosInf()) {
385             return Integer.MAX_VALUE;
386         } else if (isNegInf()) {
387             return Integer.MIN_VALUE;
388         } else if (isNaN()) {
389             return 0;
390         } else { // finite
391             return mNumerator / mDenominator;
392         }
393     }
394 
395     /**
396      * Returns the value of the specified number as a {@code long}.
397      *
398      * <p>{@link #isInfinite Finite} rationals are converted to an {@code long} value
399      * by dividing the numerator by the denominator; conversion for non-finite values happens
400      * identically to casting a floating point value to a {@code long}, in particular:
401      *
402      * <p>
403      * <ul>
404      * <li>Positive infinity saturates to the largest maximum long
405      * {@link Long#MAX_VALUE}</li>
406      * <li>Negative infinity saturates to the smallest maximum long
407      * {@link Long#MIN_VALUE}</li>
408      * <li><em>Not-A-Number (NaN)</em> returns {@code 0}.</li>
409      * </ul>
410      * </p>
411      *
412      * @return the divided value of the numerator and denominator as a {@code long}.
413      */
414     @Override
longValue()415     public long longValue() {
416         // Mimic float to long conversion rules from JLS 5.1.3
417 
418         if (isPosInf()) {
419             return Long.MAX_VALUE;
420         } else if (isNegInf()) {
421             return Long.MIN_VALUE;
422         } else if (isNaN()) {
423             return 0;
424         } else { // finite
425             return mNumerator / mDenominator;
426         }
427     }
428 
429     /**
430      * Returns the value of the specified number as a {@code short}.
431      *
432      * <p>{@link #isInfinite Finite} rationals are converted to a {@code short} value
433      * identically to {@link #intValue}; the {@code int} result is then truncated to a
434      * {@code short} before returning the value.</p>
435      *
436      * @return the divided value of the numerator and denominator as a {@code short}.
437      */
438     @Override
shortValue()439     public short shortValue() {
440         return (short) intValue();
441     }
442 
443     /**
444      * Compare this rational to the specified rational to determine their natural order.
445      *
446      * <p>{@link #NaN} is considered to be equal to itself and greater than all other
447      * {@code Rational} values. Otherwise, if the objects are not {@link #equals equal}, then
448      * the following rules apply:</p>
449      *
450      * <ul>
451      * <li>Positive infinity is greater than any other finite number (or negative infinity)
452      * <li>Negative infinity is less than any other finite number (or positive infinity)
453      * <li>The finite number represented by this rational is checked numerically
454      * against the other finite number by converting both rationals to a common denominator multiple
455      * and comparing their numerators.
456      * </ul>
457      *
458      * @param another the rational to be compared
459      *
460      * @return a negative integer, zero, or a positive integer as this object is less than,
461      *         equal to, or greater than the specified rational.
462      *
463      * @throws NullPointerException if {@code another} was {@code null}
464      */
465     @Override
compareTo(Rational another)466     public int compareTo(Rational another) {
467         checkNotNull(another, "another must not be null");
468 
469         if (equals(another)) {
470             return 0;
471         } else if (isNaN()) { // NaN is greater than the other non-NaN value
472             return 1;
473         } else if (another.isNaN()) { // the other NaN is greater than this non-NaN value
474             return -1;
475         } else if (isPosInf() || another.isNegInf()) {
476             return 1; // positive infinity is greater than any non-NaN/non-posInf value
477         } else if (isNegInf() || another.isPosInf()) {
478             return -1; // negative infinity is less than any non-NaN/non-negInf value
479         }
480 
481         // else both this and another are finite numbers
482 
483         // make the denominators the same, then compare numerators
484         long thisNumerator = ((long)mNumerator) * another.mDenominator; // long to avoid overflow
485         long otherNumerator = ((long)another.mNumerator) * mDenominator; // long to avoid overflow
486 
487         // avoid underflow from subtraction by doing comparisons
488         if (thisNumerator < otherNumerator) {
489             return -1;
490         } else if (thisNumerator > otherNumerator) {
491             return 1;
492         } else {
493             // This should be covered by #equals, but have this code path just in case
494             return 0;
495         }
496     }
497 
498     /*
499      * Serializable implementation.
500      *
501      * The following methods are omitted:
502      * >> writeObject - the default is sufficient (field by field serialization)
503      * >> readObjectNoData - the default is sufficient (0s for both fields is a NaN)
504      */
505 
506     /**
507      * writeObject with default serialized form - guards against
508      * deserializing non-reduced forms of the rational.
509      *
510      * @throws InvalidObjectException if the invariants were violated
511      */
readObject(java.io.ObjectInputStream in)512     private void readObject(java.io.ObjectInputStream in)
513             throws IOException, ClassNotFoundException {
514         in.defaultReadObject();
515 
516         /*
517          * Guard against trying to deserialize illegal values (in this case, ones
518          * that don't have a standard reduced form).
519          *
520          * - Non-finite values must be one of [0, 1], [0, 0], [0, 1], [0, -1]
521          * - Finite values must always have their greatest common divisor as 1
522          */
523 
524         if (mNumerator == 0) { // either zero or NaN
525             if (mDenominator == 1 || mDenominator == 0) {
526                 return;
527             }
528             throw new InvalidObjectException(
529                     "Rational must be deserialized from a reduced form for zero values");
530         } else if (mDenominator == 0) { // either positive or negative infinity
531             if (mNumerator == 1 || mNumerator == -1) {
532                 return;
533             }
534             throw new InvalidObjectException(
535                     "Rational must be deserialized from a reduced form for infinity values");
536         } else { // finite value
537             if (gcd(mNumerator, mDenominator) > 1) {
538                 throw new InvalidObjectException(
539                         "Rational must be deserialized from a reduced form for finite values");
540             }
541         }
542     }
543 
invalidRational(String s)544     private static NumberFormatException invalidRational(String s) {
545         throw new NumberFormatException("Invalid Rational: \"" + s + "\"");
546     }
547 
548     /**
549      * Parses the specified string as a rational value.
550      * <p>The ASCII characters {@code \}{@code u003a} (':') and
551      * {@code \}{@code u002f} ('/') are recognized as separators between
552      * the numerator and denumerator.</p>
553      * <p>
554      * For any {@code Rational r}: {@code Rational.parseRational(r.toString()).equals(r)}.
555      * However, the method also handles rational numbers expressed in the
556      * following forms:</p>
557      * <p>
558      * "<i>num</i>{@code /}<i>den</i>" or
559      * "<i>num</i>{@code :}<i>den</i>" {@code => new Rational(num, den);},
560      * where <i>num</i> and <i>den</i> are string integers potentially
561      * containing a sign, such as "-10", "+7" or "5".</p>
562      *
563      * <pre>{@code
564      * Rational.parseRational("3:+6").equals(new Rational(1, 2)) == true
565      * Rational.parseRational("-3/-6").equals(new Rational(1, 2)) == true
566      * Rational.parseRational("4.56") => throws NumberFormatException
567      * }</pre>
568      *
569      * @param string the string representation of a rational value.
570      * @return the rational value represented by {@code string}.
571      *
572      * @throws NumberFormatException if {@code string} cannot be parsed
573      * as a rational value.
574      * @throws NullPointerException if {@code string} was {@code null}
575      */
parseRational(String string)576     public static Rational parseRational(String string)
577             throws NumberFormatException {
578         checkNotNull(string, "string must not be null");
579 
580         if (string.equals("NaN")) {
581             return NaN;
582         } else if (string.equals("Infinity")) {
583             return POSITIVE_INFINITY;
584         } else if (string.equals("-Infinity")) {
585             return NEGATIVE_INFINITY;
586         }
587 
588         int sep_ix = string.indexOf(':');
589         if (sep_ix < 0) {
590             sep_ix = string.indexOf('/');
591         }
592         if (sep_ix < 0) {
593             throw invalidRational(string);
594         }
595         try {
596             return new Rational(Integer.parseInt(string.substring(0, sep_ix)),
597                     Integer.parseInt(string.substring(sep_ix + 1)));
598         } catch (NumberFormatException e) {
599             throw invalidRational(string);
600         }
601     }
602 }
603