1b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin/* 2b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * Copyright (C) 2013 The Android Open Source Project 3b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * 4b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * Licensed under the Apache License, Version 2.0 (the "License"); 5b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * you may not use this file except in compliance with the License. 6b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * You may obtain a copy of the License at 7b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * 8b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * http://www.apache.org/licenses/LICENSE-2.0 9b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * 10b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * Unless required by applicable law or agreed to in writing, software 11b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * distributed under the License is distributed on an "AS IS" BASIS, 12b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * See the License for the specific language governing permissions and 14b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * limitations under the License. 15b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin */ 1672f9f0a96e4476ef231d5001cb30521ad4ce5b1eIgor Murashkinpackage android.util; 17b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin 18007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkinimport static com.android.internal.util.Preconditions.*; 19007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 20007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkinimport java.io.IOException; 21007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkinimport java.io.InvalidObjectException; 22007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 23b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin/** 2472f9f0a96e4476ef231d5001cb30521ad4ce5b1eIgor Murashkin * <p>An immutable data type representation a rational number.</p> 2572f9f0a96e4476ef231d5001cb30521ad4ce5b1eIgor Murashkin * 2672f9f0a96e4476ef231d5001cb30521ad4ce5b1eIgor Murashkin * <p>Contains a pair of {@code int}s representing the numerator and denominator of a 2772f9f0a96e4476ef231d5001cb30521ad4ce5b1eIgor Murashkin * Rational number. </p> 28b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin */ 29007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkinpublic final class Rational extends Number implements Comparable<Rational> { 30007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin /** 31007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * Constant for the <em>Not-a-Number (NaN)</em> value of the {@code Rational} type. 32007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 33007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <p>A {@code NaN} value is considered to be equal to itself (that is {@code NaN.equals(NaN)} 34007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * will return {@code true}; it is always greater than any non-{@code NaN} value (that is 35007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * {@code NaN.compareTo(notNaN)} will return a number greater than {@code 0}).</p> 36007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 37007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <p>Equivalent to constructing a new rational with both the numerator and denominator 38007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * equal to {@code 0}.</p> 39007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin */ 40007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin public static final Rational NaN = new Rational(0, 0); 41007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 42007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin /** 43007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * Constant for the positive infinity value of the {@code Rational} type. 44007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 45007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <p>Equivalent to constructing a new rational with a positive numerator and a denominator 46007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * equal to {@code 0}.</p> 47007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin */ 48007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin public static final Rational POSITIVE_INFINITY = new Rational(1, 0); 49007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 50007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin /** 51007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * Constant for the negative infinity value of the {@code Rational} type. 52007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 53007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <p>Equivalent to constructing a new rational with a negative numerator and a denominator 54007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * equal to {@code 0}.</p> 55007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin */ 56007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin public static final Rational NEGATIVE_INFINITY = new Rational(-1, 0); 57007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 58007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin /** 59007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * Constant for the zero value of the {@code Rational} type. 60007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 61007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <p>Equivalent to constructing a new rational with a numerator equal to {@code 0} and 62007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * any non-zero denominator.</p> 63007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin */ 64007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin public static final Rational ZERO = new Rational(0, 1); 65007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 66007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin /** 67007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * Unique version number per class to be compliant with {@link java.io.Serializable}. 68007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 69007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <p>Increment each time the fields change in any way.</p> 70007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin */ 71007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin private static final long serialVersionUID = 1L; 72007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 73007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin /* 74007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * Do not change the order of these fields or add new instance fields to maintain the 75007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * Serializable compatibility across API revisions. 76007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin */ 77b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin private final int mNumerator; 78b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin private final int mDenominator; 79b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin 80b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin /** 81007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <p>Create a {@code Rational} with a given numerator and denominator.</p> 82b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * 8323c8809568b68430f875df759108c58016c44c16Timothy Knight * <p>The signs of the numerator and the denominator may be flipped such that the denominator 84007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * is always positive. Both the numerator and denominator will be converted to their reduced 85007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * forms (see {@link #equals} for more details).</p> 8623c8809568b68430f875df759108c58016c44c16Timothy Knight * 87007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <p>For example, 88007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <ul> 89007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <li>a rational of {@code 2/4} will be reduced to {@code 1/2}. 90007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <li>a rational of {@code 1/-1} will be flipped to {@code -1/1} 91007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <li>a rational of {@code 5/0} will be reduced to {@code 1/0} 92007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <li>a rational of {@code 0/5} will be reduced to {@code 0/1} 93007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * </ul> 94007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * </p> 95b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * 96b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * @param numerator the numerator of the rational 97b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * @param denominator the denominator of the rational 98007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 99007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * @see #equals 100b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin */ 101b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin public Rational(int numerator, int denominator) { 102b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin 103b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin if (denominator < 0) { 104b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin numerator = -numerator; 105b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin denominator = -denominator; 106b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin } 107b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin 108007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin // Convert to reduced form 109007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin if (denominator == 0 && numerator > 0) { 110007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin mNumerator = 1; // +Inf 111007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin mDenominator = 0; 112007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } else if (denominator == 0 && numerator < 0) { 113007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin mNumerator = -1; // -Inf 114007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin mDenominator = 0; 115007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } else if (denominator == 0 && numerator == 0) { 116007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin mNumerator = 0; // NaN 117007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin mDenominator = 0; 118007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } else if (numerator == 0) { 119007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin mNumerator = 0; 120007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin mDenominator = 1; 121007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } else { 122007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin int gcd = gcd(numerator, denominator); 123007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 124007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin mNumerator = numerator / gcd; 125007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin mDenominator = denominator / gcd; 126007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } 127b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin } 128b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin 129b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin /** 130b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * Gets the numerator of the rational. 131007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 132007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <p>The numerator will always return {@code 1} if this rational represents 133007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * infinity (that is, the denominator is {@code 0}).</p> 134b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin */ 135b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin public int getNumerator() { 136b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin return mNumerator; 137b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin } 138b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin 139b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin /** 140b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * Gets the denominator of the rational 141007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 142007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <p>The denominator may return {@code 0}, in which case the rational may represent 143007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * positive infinity (if the numerator was positive), negative infinity (if the numerator 144007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * was negative), or {@code NaN} (if the numerator was {@code 0}).</p> 145007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 146007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <p>The denominator will always return {@code 1} if the numerator is {@code 0}. 147b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin */ 148b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin public int getDenominator() { 149b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin return mDenominator; 150b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin } 151b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin 152007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin /** 153007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * Indicates whether this rational is a <em>Not-a-Number (NaN)</em> value. 154007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 155007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <p>A {@code NaN} value occurs when both the numerator and the denominator are {@code 0}.</p> 156007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 157007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * @return {@code true} if this rational is a <em>Not-a-Number (NaN)</em> value; 158007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * {@code false} if this is a (potentially infinite) number value 159007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin */ 160007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin public boolean isNaN() { 16123c8809568b68430f875df759108c58016c44c16Timothy Knight return mDenominator == 0 && mNumerator == 0; 16223c8809568b68430f875df759108c58016c44c16Timothy Knight } 16323c8809568b68430f875df759108c58016c44c16Timothy Knight 164007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin /** 165007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * Indicates whether this rational represents an infinite value. 166007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 167007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <p>An infinite value occurs when the denominator is {@code 0} (but the numerator is not).</p> 168007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 169007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * @return {@code true} if this rational is a (positive or negative) infinite value; 170007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * {@code false} if this is a finite number value (or {@code NaN}) 171007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin */ 172007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin public boolean isInfinite() { 173007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return mNumerator != 0 && mDenominator == 0; 174007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } 175007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 176007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin /** 177007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * Indicates whether this rational represents a finite value. 178007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 179007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <p>A finite value occurs when the denominator is not {@code 0}; in other words 180007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * the rational is neither infinity or {@code NaN}.</p> 181007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 182007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * @return {@code true} if this rational is a (positive or negative) infinite value; 183007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * {@code false} if this is a finite number value (or {@code NaN}) 184007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin */ 185007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin public boolean isFinite() { 186007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return mDenominator != 0; 187007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } 188007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 189007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin /** 190007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * Indicates whether this rational represents a zero value. 191007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 192007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <p>A zero value is a {@link #isFinite finite} rational with a numerator of {@code 0}.</p> 193007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 194007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * @return {@code true} if this rational is finite zero value; 195007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * {@code false} otherwise 196007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin */ 197007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin public boolean isZero() { 198007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return isFinite() && mNumerator == 0; 199007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } 200007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 201007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin private boolean isPosInf() { 20223c8809568b68430f875df759108c58016c44c16Timothy Knight return mDenominator == 0 && mNumerator > 0; 20323c8809568b68430f875df759108c58016c44c16Timothy Knight } 20423c8809568b68430f875df759108c58016c44c16Timothy Knight 20523c8809568b68430f875df759108c58016c44c16Timothy Knight private boolean isNegInf() { 20623c8809568b68430f875df759108c58016c44c16Timothy Knight return mDenominator == 0 && mNumerator < 0; 20723c8809568b68430f875df759108c58016c44c16Timothy Knight } 20823c8809568b68430f875df759108c58016c44c16Timothy Knight 209b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin /** 210b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * <p>Compare this Rational to another object and see if they are equal.</p> 211b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * 212007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <p>A Rational object can only be equal to another Rational object (comparing against any 213007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * other type will return {@code false}).</p> 214b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * 21523c8809568b68430f875df759108c58016c44c16Timothy Knight * <p>A Rational object is considered equal to another Rational object if and only if one of 216007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * the following holds:</p> 217007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <ul><li>Both are {@code NaN}</li> 21823c8809568b68430f875df759108c58016c44c16Timothy Knight * <li>Both are infinities of the same sign</li> 21923c8809568b68430f875df759108c58016c44c16Timothy Knight * <li>Both have the same numerator and denominator in their reduced form</li> 22023c8809568b68430f875df759108c58016c44c16Timothy Knight * </ul> 221b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * 222b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * <p>A reduced form of a Rational is calculated by dividing both the numerator and the 223b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * denominator by their greatest common divisor.</p> 224b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * 2253c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * <pre>{@code 226007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * (new Rational(1, 2)).equals(new Rational(1, 2)) == true // trivially true 227007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * (new Rational(2, 3)).equals(new Rational(1, 2)) == false // trivially false 228007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * (new Rational(1, 2)).equals(new Rational(2, 4)) == true // true after reduction 229007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * (new Rational(0, 0)).equals(new Rational(0, 0)) == true // NaN.equals(NaN) 230007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * (new Rational(1, 0)).equals(new Rational(5, 0)) == true // both are +infinity 231007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * (new Rational(1, 0)).equals(new Rational(-1, 0)) == false // +infinity != -infinity 2323c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * }</pre> 233b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * 234b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * @param obj a reference to another object 235b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * 23624eb8a313f1a80a35566b8dc456ec2684a05a22eBenjamin Hendricks * @return A boolean that determines whether or not the two Rational objects are equal. 237b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin */ 238b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin @Override 239b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin public boolean equals(Object obj) { 240007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return obj instanceof Rational && equals((Rational) obj); 241007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } 242007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 243007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin private boolean equals(Rational other) { 244007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return (mNumerator == other.mNumerator && mDenominator == other.mDenominator); 245b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin } 246b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin 247007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin /** 248007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * Return a string representation of this rational, e.g. {@code "1/2"}. 249007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 250007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <p>The following rules of conversion apply: 251007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <ul> 252007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <li>{@code NaN} values will return {@code "NaN"} 253007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <li>Positive infinity values will return {@code "Infinity"} 254007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <li>Negative infinity values will return {@code "-Infinity"} 255007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <li>All other values will return {@code "numerator/denominator"} where {@code numerator} 256007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * and {@code denominator} are substituted with the appropriate numerator and denominator 257007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * values. 258007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * </ul></p> 259007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin */ 260b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin @Override 261b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin public String toString() { 26223c8809568b68430f875df759108c58016c44c16Timothy Knight if (isNaN()) { 26323c8809568b68430f875df759108c58016c44c16Timothy Knight return "NaN"; 264007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } else if (isPosInf()) { 26523c8809568b68430f875df759108c58016c44c16Timothy Knight return "Infinity"; 26623c8809568b68430f875df759108c58016c44c16Timothy Knight } else if (isNegInf()) { 26723c8809568b68430f875df759108c58016c44c16Timothy Knight return "-Infinity"; 26823c8809568b68430f875df759108c58016c44c16Timothy Knight } else { 26923c8809568b68430f875df759108c58016c44c16Timothy Knight return mNumerator + "/" + mDenominator; 27023c8809568b68430f875df759108c58016c44c16Timothy Knight } 27123c8809568b68430f875df759108c58016c44c16Timothy Knight } 27223c8809568b68430f875df759108c58016c44c16Timothy Knight 27323c8809568b68430f875df759108c58016c44c16Timothy Knight /** 27423c8809568b68430f875df759108c58016c44c16Timothy Knight * <p>Convert to a floating point representation.</p> 27523c8809568b68430f875df759108c58016c44c16Timothy Knight * 27623c8809568b68430f875df759108c58016c44c16Timothy Knight * @return The floating point representation of this rational number. 27723c8809568b68430f875df759108c58016c44c16Timothy Knight * @hide 27823c8809568b68430f875df759108c58016c44c16Timothy Knight */ 27923c8809568b68430f875df759108c58016c44c16Timothy Knight public float toFloat() { 280007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin // TODO: remove this duplicate function (used in CTS and the shim) 281007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return floatValue(); 282b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin } 283b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin 2843c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin /** 2853c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * {@inheritDoc} 2863c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin */ 287b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin @Override 288b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin public int hashCode() { 2893c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin // Bias the hash code for the first (2^16) values for both numerator and denominator 2903c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin int numeratorFlipped = mNumerator << 16 | mNumerator >>> 16; 291b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin 2923c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin return mDenominator ^ numeratorFlipped; 293b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin } 294b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin 295b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin /** 296b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * Calculates the greatest common divisor using Euclid's algorithm. 297b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * 298007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <p><em>Visible for testing only.</em></p> 299007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 300007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * @param numerator the numerator in a fraction 301007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * @param denominator the denominator in a fraction 302007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 30324eb8a313f1a80a35566b8dc456ec2684a05a22eBenjamin Hendricks * @return An int value representing the gcd. Always positive. 304b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * @hide 305b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin */ 306007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin public static int gcd(int numerator, int denominator) { 307007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin /* 308b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * Non-recursive implementation of Euclid's algorithm: 309b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * 310b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * gcd(a, 0) := a 311b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * gcd(a, b) := gcd(b, a mod b) 312b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin * 313b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin */ 314007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin int a = numerator; 315007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin int b = denominator; 316b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin 317b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin while (b != 0) { 318b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin int oldB = b; 319b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin 320b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin b = a % b; 321b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin a = oldB; 322b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin } 323b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin 324b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin return Math.abs(a); 325b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin } 326007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 327007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin /** 328007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * Returns the value of the specified number as a {@code double}. 329007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 330007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <p>The {@code double} is calculated by converting both the numerator and denominator 331007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * to a {@code double}; then returning the result of dividing the numerator by the 332007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * denominator.</p> 333007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 334007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * @return the divided value of the numerator and denominator as a {@code double}. 335007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin */ 336007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin @Override 337007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin public double doubleValue() { 338007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin double num = mNumerator; 339007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin double den = mDenominator; 340007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 341007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return num / den; 342007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } 343007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 344007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin /** 345007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * Returns the value of the specified number as a {@code float}. 346007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 347007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <p>The {@code float} is calculated by converting both the numerator and denominator 348007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * to a {@code float}; then returning the result of dividing the numerator by the 349007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * denominator.</p> 350007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 351007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * @return the divided value of the numerator and denominator as a {@code float}. 352007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin */ 353007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin @Override 354007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin public float floatValue() { 355007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin float num = mNumerator; 356007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin float den = mDenominator; 357007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 358007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return num / den; 359007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } 360007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 361007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin /** 362007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * Returns the value of the specified number as a {@code int}. 363007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 364007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <p>{@link #isInfinite Finite} rationals are converted to an {@code int} value 365007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * by dividing the numerator by the denominator; conversion for non-finite values happens 366007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * identically to casting a floating point value to an {@code int}, in particular: 367007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 368007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <p> 369007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <ul> 370007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <li>Positive infinity saturates to the largest maximum integer 371007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * {@link Integer#MAX_VALUE}</li> 372007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <li>Negative infinity saturates to the smallest maximum integer 373007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * {@link Integer#MIN_VALUE}</li> 374007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <li><em>Not-A-Number (NaN)</em> returns {@code 0}.</li> 375007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * </ul> 376007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * </p> 377007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 378007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * @return the divided value of the numerator and denominator as a {@code int}. 379007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin */ 380007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin @Override 381007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin public int intValue() { 382007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin // Mimic float to int conversion rules from JLS 5.1.3 383007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 384007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin if (isPosInf()) { 385007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return Integer.MAX_VALUE; 386007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } else if (isNegInf()) { 387007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return Integer.MIN_VALUE; 388007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } else if (isNaN()) { 389007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return 0; 390007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } else { // finite 391007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return mNumerator / mDenominator; 392007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } 393007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } 394007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 395007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin /** 396007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * Returns the value of the specified number as a {@code long}. 397007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 398007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <p>{@link #isInfinite Finite} rationals are converted to an {@code long} value 399007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * by dividing the numerator by the denominator; conversion for non-finite values happens 400007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * identically to casting a floating point value to a {@code long}, in particular: 401007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 402007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <p> 403007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <ul> 404007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <li>Positive infinity saturates to the largest maximum long 405007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * {@link Long#MAX_VALUE}</li> 406007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <li>Negative infinity saturates to the smallest maximum long 407007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * {@link Long#MIN_VALUE}</li> 408007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <li><em>Not-A-Number (NaN)</em> returns {@code 0}.</li> 409007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * </ul> 410007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * </p> 411007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 412007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * @return the divided value of the numerator and denominator as a {@code long}. 413007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin */ 414007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin @Override 415007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin public long longValue() { 416007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin // Mimic float to long conversion rules from JLS 5.1.3 417007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 418007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin if (isPosInf()) { 419007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return Long.MAX_VALUE; 420007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } else if (isNegInf()) { 421007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return Long.MIN_VALUE; 422007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } else if (isNaN()) { 423007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return 0; 424007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } else { // finite 425007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return mNumerator / mDenominator; 426007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } 427007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } 428007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 429007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin /** 430007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * Returns the value of the specified number as a {@code short}. 431007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 432007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <p>{@link #isInfinite Finite} rationals are converted to a {@code short} value 433007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * identically to {@link #intValue}; the {@code int} result is then truncated to a 434007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * {@code short} before returning the value.</p> 435007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 436007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * @return the divided value of the numerator and denominator as a {@code short}. 437007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin */ 438007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin @Override 439007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin public short shortValue() { 440007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return (short) intValue(); 441007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } 442007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 443007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin /** 444007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * Compare this rational to the specified rational to determine their natural order. 445007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 446007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <p>{@link #NaN} is considered to be equal to itself and greater than all other 447007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * {@code Rational} values. Otherwise, if the objects are not {@link #equals equal}, then 448007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * the following rules apply:</p> 449007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 450007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <ul> 451007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <li>Positive infinity is greater than any other finite number (or negative infinity) 452007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <li>Negative infinity is less than any other finite number (or positive infinity) 453007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * <li>The finite number represented by this rational is checked numerically 454007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * against the other finite number by converting both rationals to a common denominator multiple 455007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * and comparing their numerators. 456007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * </ul> 457007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 458007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * @param another the rational to be compared 459007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 460007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * @return a negative integer, zero, or a positive integer as this object is less than, 461007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * equal to, or greater than the specified rational. 462007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 463007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * @throws NullPointerException if {@code another} was {@code null} 464007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin */ 465007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin @Override 466007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin public int compareTo(Rational another) { 467007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin checkNotNull(another, "another must not be null"); 468007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 469007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin if (equals(another)) { 470007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return 0; 471007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } else if (isNaN()) { // NaN is greater than the other non-NaN value 472007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return 1; 473007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } else if (another.isNaN()) { // the other NaN is greater than this non-NaN value 474007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return -1; 475007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } else if (isPosInf() || another.isNegInf()) { 476007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return 1; // positive infinity is greater than any non-NaN/non-posInf value 477007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } else if (isNegInf() || another.isPosInf()) { 478007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return -1; // negative infinity is less than any non-NaN/non-negInf value 479007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } 480007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 481007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin // else both this and another are finite numbers 482007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 483007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin // make the denominators the same, then compare numerators 484007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin long thisNumerator = ((long)mNumerator) * another.mDenominator; // long to avoid overflow 485007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin long otherNumerator = ((long)another.mNumerator) * mDenominator; // long to avoid overflow 486007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 487007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin // avoid underflow from subtraction by doing comparisons 488007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin if (thisNumerator < otherNumerator) { 489007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return -1; 490007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } else if (thisNumerator > otherNumerator) { 491007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return 1; 492007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } else { 493007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin // This should be covered by #equals, but have this code path just in case 494007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return 0; 495007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } 496007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } 497007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 498007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin /* 499007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * Serializable implementation. 500007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 501007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * The following methods are omitted: 502007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * >> writeObject - the default is sufficient (field by field serialization) 503007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * >> readObjectNoData - the default is sufficient (0s for both fields is a NaN) 504007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin */ 505007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 506007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin /** 507007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * writeObject with default serialized form - guards against 508007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * deserializing non-reduced forms of the rational. 509007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 510007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * @throws InvalidObjectException if the invariants were violated 511007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin */ 512007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin private void readObject(java.io.ObjectInputStream in) 513007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin throws IOException, ClassNotFoundException { 514007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin in.defaultReadObject(); 515007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 516007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin /* 517007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * Guard against trying to deserialize illegal values (in this case, ones 518007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * that don't have a standard reduced form). 519007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * 520007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * - Non-finite values must be one of [0, 1], [0, 0], [0, 1], [0, -1] 521007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin * - Finite values must always have their greatest common divisor as 1 522007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin */ 523007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin 524007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin if (mNumerator == 0) { // either zero or NaN 525007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin if (mDenominator == 1 || mDenominator == 0) { 526007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return; 527007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } 528007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin throw new InvalidObjectException( 529007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin "Rational must be deserialized from a reduced form for zero values"); 530007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } else if (mDenominator == 0) { // either positive or negative infinity 531007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin if (mNumerator == 1 || mNumerator == -1) { 532007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin return; 533007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } 534007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin throw new InvalidObjectException( 535007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin "Rational must be deserialized from a reduced form for infinity values"); 536007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } else { // finite value 537007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin if (gcd(mNumerator, mDenominator) > 1) { 538007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin throw new InvalidObjectException( 539b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar "Rational must be deserialized from a reduced form for finite values"); 540007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } 541007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } 542007bfb14d2d720cdd699cfbb36ce206246901cefIgor Murashkin } 543b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar 544b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar private static NumberFormatException invalidRational(String s) { 545b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar throw new NumberFormatException("Invalid Rational: \"" + s + "\""); 546b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar } 547b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar 548b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar /** 549b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * Parses the specified string as a rational value. 550b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * <p>The ASCII characters {@code \}{@code u003a} (':') and 551b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * {@code \}{@code u002f} ('/') are recognized as separators between 552b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * the numerator and denumerator.</p> 553b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * <p> 554b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * For any {@code Rational r}: {@code Rational.parseRational(r.toString()).equals(r)}. 555b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * However, the method also handles rational numbers expressed in the 556b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * following forms:</p> 557b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * <p> 558b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * "<i>num</i>{@code /}<i>den</i>" or 559b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * "<i>num</i>{@code :}<i>den</i>" {@code => new Rational(num, den);}, 560b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * where <i>num</i> and <i>den</i> are string integers potentially 561b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * containing a sign, such as "-10", "+7" or "5".</p> 562b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * 563b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * <pre>{@code 564b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * Rational.parseRational("3:+6").equals(new Rational(1, 2)) == true 565b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * Rational.parseRational("-3/-6").equals(new Rational(1, 2)) == true 566b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * Rational.parseRational("4.56") => throws NumberFormatException 567b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * }</pre> 568b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * 569b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * @param string the string representation of a rational value. 570b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * @return the rational value represented by {@code string}. 571b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * 572b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * @throws NumberFormatException if {@code string} cannot be parsed 573b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * as a rational value. 574b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar * @throws NullPointerException if {@code string} was {@code null} 575b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar */ 576b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar public static Rational parseRational(String string) 577b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar throws NumberFormatException { 578b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar checkNotNull(string, "string must not be null"); 579b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar 580b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar if (string.equals("NaN")) { 581b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar return NaN; 582b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar } else if (string.equals("Infinity")) { 583b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar return POSITIVE_INFINITY; 584b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar } else if (string.equals("-Infinity")) { 585b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar return NEGATIVE_INFINITY; 586b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar } 587b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar 588b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar int sep_ix = string.indexOf(':'); 589b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar if (sep_ix < 0) { 590b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar sep_ix = string.indexOf('/'); 591b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar } 592b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar if (sep_ix < 0) { 593b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar throw invalidRational(string); 594b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar } 595b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar try { 596b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar return new Rational(Integer.parseInt(string.substring(0, sep_ix)), 597b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar Integer.parseInt(string.substring(sep_ix + 1))); 598b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar } catch (NumberFormatException e) { 599b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar throw invalidRational(string); 600b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar } 601b1a236b85fa8f3f46e3f6b76a7bf6f72faf9ee5dLajos Molnar } 602b519cc52ecba8f44da31173c9fc90a7b66d52b79Igor Murashkin} 603