| 1 | /*
|
|---|
| 2 | * Copyright 2002-2017 Drew Noakes
|
|---|
| 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 | * More information about this project is available at:
|
|---|
| 17 | *
|
|---|
| 18 | * https://drewnoakes.com/code/exif/
|
|---|
| 19 | * https://github.com/drewnoakes/metadata-extractor
|
|---|
| 20 | */
|
|---|
| 21 |
|
|---|
| 22 | package com.drew.lang;
|
|---|
| 23 |
|
|---|
| 24 | import com.drew.lang.annotations.NotNull;
|
|---|
| 25 | import com.drew.lang.annotations.Nullable;
|
|---|
| 26 |
|
|---|
| 27 | import java.io.Serializable;
|
|---|
| 28 |
|
|---|
| 29 | /**
|
|---|
| 30 | * Immutable class for holding a rational number without loss of precision. Provides
|
|---|
| 31 | * a familiar representation via {@link Rational#toString} in form <code>numerator/denominator</code>.
|
|---|
| 32 | *
|
|---|
| 33 | * Note that any value with a numerator of zero will be treated as zero, even if the
|
|---|
| 34 | * denominator is also zero.
|
|---|
| 35 | *
|
|---|
| 36 | * @author Drew Noakes https://drewnoakes.com
|
|---|
| 37 | */
|
|---|
| 38 | @SuppressWarnings("WeakerAccess")
|
|---|
| 39 | public class Rational extends java.lang.Number implements Comparable<Rational>, Serializable
|
|---|
| 40 | {
|
|---|
| 41 | private static final long serialVersionUID = 510688928138848770L;
|
|---|
| 42 |
|
|---|
| 43 | /** Holds the numerator. */
|
|---|
| 44 | private final long _numerator;
|
|---|
| 45 |
|
|---|
| 46 | /** Holds the denominator. */
|
|---|
| 47 | private final long _denominator;
|
|---|
| 48 |
|
|---|
| 49 | /**
|
|---|
| 50 | * Creates a new instance of Rational. Rational objects are immutable, so
|
|---|
| 51 | * once you've set your numerator and denominator values here, you're stuck
|
|---|
| 52 | * with them!
|
|---|
| 53 | */
|
|---|
| 54 | public Rational(long numerator, long denominator)
|
|---|
| 55 | {
|
|---|
| 56 | _numerator = numerator;
|
|---|
| 57 | _denominator = denominator;
|
|---|
| 58 | }
|
|---|
| 59 |
|
|---|
| 60 | /**
|
|---|
| 61 | * Returns the value of the specified number as a <code>double</code>.
|
|---|
| 62 | * This may involve rounding.
|
|---|
| 63 | *
|
|---|
| 64 | * @return the numeric value represented by this object after conversion
|
|---|
| 65 | * to type <code>double</code>.
|
|---|
| 66 | */
|
|---|
| 67 | @Override
|
|---|
| 68 | public double doubleValue()
|
|---|
| 69 | {
|
|---|
| 70 | return _numerator == 0
|
|---|
| 71 | ? 0.0
|
|---|
| 72 | : (double) _numerator / (double) _denominator;
|
|---|
| 73 | }
|
|---|
| 74 |
|
|---|
| 75 | /**
|
|---|
| 76 | * Returns the value of the specified number as a <code>float</code>.
|
|---|
| 77 | * This may involve rounding.
|
|---|
| 78 | *
|
|---|
| 79 | * @return the numeric value represented by this object after conversion
|
|---|
| 80 | * to type <code>float</code>.
|
|---|
| 81 | */
|
|---|
| 82 | @Override
|
|---|
| 83 | public float floatValue()
|
|---|
| 84 | {
|
|---|
| 85 | return _numerator == 0
|
|---|
| 86 | ? 0.0f
|
|---|
| 87 | : (float) _numerator / (float) _denominator;
|
|---|
| 88 | }
|
|---|
| 89 |
|
|---|
| 90 | /**
|
|---|
| 91 | * Returns the value of the specified number as a <code>byte</code>.
|
|---|
| 92 | * This may involve rounding or truncation. This implementation simply
|
|---|
| 93 | * casts the result of {@link Rational#doubleValue} to <code>byte</code>.
|
|---|
| 94 | *
|
|---|
| 95 | * @return the numeric value represented by this object after conversion
|
|---|
| 96 | * to type <code>byte</code>.
|
|---|
| 97 | */
|
|---|
| 98 | @Override
|
|---|
| 99 | public final byte byteValue()
|
|---|
| 100 | {
|
|---|
| 101 | return (byte) doubleValue();
|
|---|
| 102 | }
|
|---|
| 103 |
|
|---|
| 104 | /**
|
|---|
| 105 | * Returns the value of the specified number as an <code>int</code>.
|
|---|
| 106 | * This may involve rounding or truncation. This implementation simply
|
|---|
| 107 | * casts the result of {@link Rational#doubleValue} to <code>int</code>.
|
|---|
| 108 | *
|
|---|
| 109 | * @return the numeric value represented by this object after conversion
|
|---|
| 110 | * to type <code>int</code>.
|
|---|
| 111 | */
|
|---|
| 112 | @Override
|
|---|
| 113 | public final int intValue()
|
|---|
| 114 | {
|
|---|
| 115 | return (int) doubleValue();
|
|---|
| 116 | }
|
|---|
| 117 |
|
|---|
| 118 | /**
|
|---|
| 119 | * Returns the value of the specified number as a <code>long</code>.
|
|---|
| 120 | * This may involve rounding or truncation. This implementation simply
|
|---|
| 121 | * casts the result of {@link Rational#doubleValue} to <code>long</code>.
|
|---|
| 122 | *
|
|---|
| 123 | * @return the numeric value represented by this object after conversion
|
|---|
| 124 | * to type <code>long</code>.
|
|---|
| 125 | */
|
|---|
| 126 | @Override
|
|---|
| 127 | public final long longValue()
|
|---|
| 128 | {
|
|---|
| 129 | return (long) doubleValue();
|
|---|
| 130 | }
|
|---|
| 131 |
|
|---|
| 132 | /**
|
|---|
| 133 | * Returns the value of the specified number as a <code>short</code>.
|
|---|
| 134 | * This may involve rounding or truncation. This implementation simply
|
|---|
| 135 | * casts the result of {@link Rational#doubleValue} to <code>short</code>.
|
|---|
| 136 | *
|
|---|
| 137 | * @return the numeric value represented by this object after conversion
|
|---|
| 138 | * to type <code>short</code>.
|
|---|
| 139 | */
|
|---|
| 140 | @Override
|
|---|
| 141 | public final short shortValue()
|
|---|
| 142 | {
|
|---|
| 143 | return (short) doubleValue();
|
|---|
| 144 | }
|
|---|
| 145 |
|
|---|
| 146 |
|
|---|
| 147 | /** Returns the denominator. */
|
|---|
| 148 | public final long getDenominator()
|
|---|
| 149 | {
|
|---|
| 150 | return this._denominator;
|
|---|
| 151 | }
|
|---|
| 152 |
|
|---|
| 153 | /** Returns the numerator. */
|
|---|
| 154 | public final long getNumerator()
|
|---|
| 155 | {
|
|---|
| 156 | return this._numerator;
|
|---|
| 157 | }
|
|---|
| 158 |
|
|---|
| 159 | /**
|
|---|
| 160 | * Returns the reciprocal value of this object as a new Rational.
|
|---|
| 161 | *
|
|---|
| 162 | * @return the reciprocal in a new object
|
|---|
| 163 | */
|
|---|
| 164 | @NotNull
|
|---|
| 165 | public Rational getReciprocal()
|
|---|
| 166 | {
|
|---|
| 167 | return new Rational(this._denominator, this._numerator);
|
|---|
| 168 | }
|
|---|
| 169 |
|
|---|
| 170 | /** Checks if this {@link Rational} number is an Integer, either positive or negative. */
|
|---|
| 171 | public boolean isInteger()
|
|---|
| 172 | {
|
|---|
| 173 | return _denominator == 1 ||
|
|---|
| 174 | (_denominator != 0 && (_numerator % _denominator == 0)) ||
|
|---|
| 175 | (_denominator == 0 && _numerator == 0);
|
|---|
| 176 | }
|
|---|
| 177 |
|
|---|
| 178 | /** Checks if either the numerator or denominator are zero. */
|
|---|
| 179 | public boolean isZero()
|
|---|
| 180 | {
|
|---|
| 181 | return _numerator == 0 || _denominator == 0;
|
|---|
| 182 | }
|
|---|
| 183 |
|
|---|
| 184 | /**
|
|---|
| 185 | * Returns a string representation of the object of form <code>numerator/denominator</code>.
|
|---|
| 186 | *
|
|---|
| 187 | * @return a string representation of the object.
|
|---|
| 188 | */
|
|---|
| 189 | @Override
|
|---|
| 190 | @NotNull
|
|---|
| 191 | public String toString()
|
|---|
| 192 | {
|
|---|
| 193 | return _numerator + "/" + _denominator;
|
|---|
| 194 | }
|
|---|
| 195 |
|
|---|
| 196 | /** Returns the simplest representation of this {@link Rational}'s value possible. */
|
|---|
| 197 | @NotNull
|
|---|
| 198 | public String toSimpleString(boolean allowDecimal)
|
|---|
| 199 | {
|
|---|
| 200 | if (_denominator == 0 && _numerator != 0) {
|
|---|
| 201 | return toString();
|
|---|
| 202 | } else if (isInteger()) {
|
|---|
| 203 | return Integer.toString(intValue());
|
|---|
| 204 | } else if (_numerator != 1 && _denominator % _numerator == 0) {
|
|---|
| 205 | // common factor between denominator and numerator
|
|---|
| 206 | long newDenominator = _denominator / _numerator;
|
|---|
| 207 | return new Rational(1, newDenominator).toSimpleString(allowDecimal);
|
|---|
| 208 | } else {
|
|---|
| 209 | Rational simplifiedInstance = getSimplifiedInstance();
|
|---|
| 210 | if (allowDecimal) {
|
|---|
| 211 | String doubleString = Double.toString(simplifiedInstance.doubleValue());
|
|---|
| 212 | if (doubleString.length() < 5) {
|
|---|
| 213 | return doubleString;
|
|---|
| 214 | }
|
|---|
| 215 | }
|
|---|
| 216 | return simplifiedInstance.toString();
|
|---|
| 217 | }
|
|---|
| 218 | }
|
|---|
| 219 |
|
|---|
| 220 | /**
|
|---|
| 221 | * Compares two {@link Rational} instances, returning true if they are mathematically
|
|---|
| 222 | * equivalent (in consistence with {@link Rational#equals(Object)} method).
|
|---|
| 223 | *
|
|---|
| 224 | * @param that the {@link Rational} to compare this instance to.
|
|---|
| 225 | * @return the value {@code 0} if this {@link Rational} is
|
|---|
| 226 | * equal to the argument {@link Rational} mathematically; a value less
|
|---|
| 227 | * than {@code 0} if this {@link Rational} is less
|
|---|
| 228 | * than the argument {@link Rational}; and a value greater
|
|---|
| 229 | * than {@code 0} if this {@link Rational} is greater than the argument
|
|---|
| 230 | * {@link Rational}.
|
|---|
| 231 | */
|
|---|
| 232 | public int compareTo(@NotNull Rational that) {
|
|---|
| 233 | return Double.compare(this.doubleValue(), that.doubleValue());
|
|---|
| 234 | }
|
|---|
| 235 |
|
|---|
| 236 | /**
|
|---|
| 237 | * Indicates whether this instance and <code>other</code> are numerically equal,
|
|---|
| 238 | * even if their representations differ.
|
|---|
| 239 | *
|
|---|
| 240 | * For example, 1/2 is equal to 10/20 by this method.
|
|---|
| 241 | * Similarly, 1/0 is equal to 100/0 by this method.
|
|---|
| 242 | * To test equal representations, use EqualsExact.
|
|---|
| 243 | *
|
|---|
| 244 | * @param other The rational value to compare with
|
|---|
| 245 | */
|
|---|
| 246 | public boolean equals(Rational other) {
|
|---|
| 247 | return other.doubleValue() == doubleValue();
|
|---|
| 248 | }
|
|---|
| 249 |
|
|---|
| 250 | /**
|
|---|
| 251 | * Indicates whether this instance and <code>other</code> have identical
|
|---|
| 252 | * Numerator and Denominator.
|
|---|
| 253 | * <p>
|
|---|
| 254 | * For example, 1/2 is not equal to 10/20 by this method.
|
|---|
| 255 | * Similarly, 1/0 is not equal to 100/0 by this method.
|
|---|
| 256 | * To test numerically equivalence, use Equals(Rational).</p>
|
|---|
| 257 | *
|
|---|
| 258 | * @param other The rational value to compare with
|
|---|
| 259 | */
|
|---|
| 260 | public boolean equalsExact(Rational other) {
|
|---|
| 261 | return getDenominator() == other.getDenominator() && getNumerator() == other.getNumerator();
|
|---|
| 262 | }
|
|---|
| 263 |
|
|---|
| 264 | /**
|
|---|
| 265 | * Compares two {@link Rational} instances, returning true if they are mathematically
|
|---|
| 266 | * equivalent.
|
|---|
| 267 | *
|
|---|
| 268 | * @param obj the {@link Rational} to compare this instance to.
|
|---|
| 269 | * @return true if instances are mathematically equivalent, otherwise false. Will also
|
|---|
| 270 | * return false if <code>obj</code> is not an instance of {@link Rational}.
|
|---|
| 271 | */
|
|---|
| 272 | @Override
|
|---|
| 273 | public boolean equals(@Nullable Object obj)
|
|---|
| 274 | {
|
|---|
| 275 | if (obj==null || !(obj instanceof Rational))
|
|---|
| 276 | return false;
|
|---|
| 277 | Rational that = (Rational) obj;
|
|---|
| 278 | return this.doubleValue() == that.doubleValue();
|
|---|
| 279 | }
|
|---|
| 280 |
|
|---|
| 281 | @Override
|
|---|
| 282 | public int hashCode()
|
|---|
| 283 | {
|
|---|
| 284 | return (23 * (int)_denominator) + (int)_numerator;
|
|---|
| 285 | }
|
|---|
| 286 |
|
|---|
| 287 | /**
|
|---|
| 288 | * <p>
|
|---|
| 289 | * Simplifies the representation of this {@link Rational} number.</p>
|
|---|
| 290 | * <p>
|
|---|
| 291 | * For example, 5/10 simplifies to 1/2 because both Numerator
|
|---|
| 292 | * and Denominator share a common factor of 5.</p>
|
|---|
| 293 | * <p>
|
|---|
| 294 | * Uses the Euclidean Algorithm to find the greatest common divisor.</p>
|
|---|
| 295 | *
|
|---|
| 296 | * @return A simplified instance if one exists, otherwise a copy of the original value.
|
|---|
| 297 | */
|
|---|
| 298 | @NotNull
|
|---|
| 299 | public Rational getSimplifiedInstance()
|
|---|
| 300 | {
|
|---|
| 301 | long gcd = GCD(_numerator, _denominator);
|
|---|
| 302 |
|
|---|
| 303 | return new Rational(_numerator / gcd, _denominator / gcd);
|
|---|
| 304 | }
|
|---|
| 305 |
|
|---|
| 306 | private static long GCD(long a, long b)
|
|---|
| 307 | {
|
|---|
| 308 | if (a < 0)
|
|---|
| 309 | a = -a;
|
|---|
| 310 | if (b < 0)
|
|---|
| 311 | b = -b;
|
|---|
| 312 |
|
|---|
| 313 | while (a != 0 && b != 0)
|
|---|
| 314 | {
|
|---|
| 315 | if (a > b)
|
|---|
| 316 | a %= b;
|
|---|
| 317 | else
|
|---|
| 318 | b %= a;
|
|---|
| 319 | }
|
|---|
| 320 |
|
|---|
| 321 | return a == 0 ? b : a;
|
|---|
| 322 | }
|
|---|
| 323 | }
|
|---|