| 1 | /*
|
|---|
| 2 | * Copyright 2002-2012 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 | * http://drewnoakes.com/code/exif/
|
|---|
| 19 | * http://code.google.com/p/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 toString() in form <code>numerator/denominator</code>.
|
|---|
| 32 | *
|
|---|
| 33 | * @author Drew Noakes http://drewnoakes.com
|
|---|
| 34 | */
|
|---|
| 35 | public class Rational extends java.lang.Number implements Serializable
|
|---|
| 36 | {
|
|---|
| 37 | private static final long serialVersionUID = 510688928138848770L;
|
|---|
| 38 |
|
|---|
| 39 | /** Holds the numerator. */
|
|---|
| 40 | private final long _numerator;
|
|---|
| 41 |
|
|---|
| 42 | /** Holds the denominator. */
|
|---|
| 43 | private final long _denominator;
|
|---|
| 44 |
|
|---|
| 45 | /**
|
|---|
| 46 | * Creates a new instance of Rational. Rational objects are immutable, so
|
|---|
| 47 | * once you've set your numerator and denominator values here, you're stuck
|
|---|
| 48 | * with them!
|
|---|
| 49 | */
|
|---|
| 50 | public Rational(long numerator, long denominator)
|
|---|
| 51 | {
|
|---|
| 52 | _numerator = numerator;
|
|---|
| 53 | _denominator = denominator;
|
|---|
| 54 | }
|
|---|
| 55 |
|
|---|
| 56 | /**
|
|---|
| 57 | * Returns the value of the specified number as a <code>double</code>.
|
|---|
| 58 | * This may involve rounding.
|
|---|
| 59 | *
|
|---|
| 60 | * @return the numeric value represented by this object after conversion
|
|---|
| 61 | * to type <code>double</code>.
|
|---|
| 62 | */
|
|---|
| 63 | public double doubleValue()
|
|---|
| 64 | {
|
|---|
| 65 | return (double) _numerator / (double) _denominator;
|
|---|
| 66 | }
|
|---|
| 67 |
|
|---|
| 68 | /**
|
|---|
| 69 | * Returns the value of the specified number as a <code>float</code>.
|
|---|
| 70 | * This may involve rounding.
|
|---|
| 71 | *
|
|---|
| 72 | * @return the numeric value represented by this object after conversion
|
|---|
| 73 | * to type <code>float</code>.
|
|---|
| 74 | */
|
|---|
| 75 | public float floatValue()
|
|---|
| 76 | {
|
|---|
| 77 | return (float) _numerator / (float) _denominator;
|
|---|
| 78 | }
|
|---|
| 79 |
|
|---|
| 80 | /**
|
|---|
| 81 | * Returns the value of the specified number as a <code>byte</code>.
|
|---|
| 82 | * This may involve rounding or truncation. This implementation simply
|
|---|
| 83 | * casts the result of <code>doubleValue()</code> to <code>byte</code>.
|
|---|
| 84 | *
|
|---|
| 85 | * @return the numeric value represented by this object after conversion
|
|---|
| 86 | * to type <code>byte</code>.
|
|---|
| 87 | */
|
|---|
| 88 | public final byte byteValue()
|
|---|
| 89 | {
|
|---|
| 90 | return (byte) doubleValue();
|
|---|
| 91 | }
|
|---|
| 92 |
|
|---|
| 93 | /**
|
|---|
| 94 | * Returns the value of the specified number as an <code>int</code>.
|
|---|
| 95 | * This may involve rounding or truncation. This implementation simply
|
|---|
| 96 | * casts the result of <code>doubleValue()</code> to <code>int</code>.
|
|---|
| 97 | *
|
|---|
| 98 | * @return the numeric value represented by this object after conversion
|
|---|
| 99 | * to type <code>int</code>.
|
|---|
| 100 | */
|
|---|
| 101 | public final int intValue()
|
|---|
| 102 | {
|
|---|
| 103 | return (int) doubleValue();
|
|---|
| 104 | }
|
|---|
| 105 |
|
|---|
| 106 | /**
|
|---|
| 107 | * Returns the value of the specified number as a <code>long</code>.
|
|---|
| 108 | * This may involve rounding or truncation. This implementation simply
|
|---|
| 109 | * casts the result of <code>doubleValue()</code> to <code>long</code>.
|
|---|
| 110 | *
|
|---|
| 111 | * @return the numeric value represented by this object after conversion
|
|---|
| 112 | * to type <code>long</code>.
|
|---|
| 113 | */
|
|---|
| 114 | public final long longValue()
|
|---|
| 115 | {
|
|---|
| 116 | return (long) doubleValue();
|
|---|
| 117 | }
|
|---|
| 118 |
|
|---|
| 119 | /**
|
|---|
| 120 | * Returns the value of the specified number as a <code>short</code>.
|
|---|
| 121 | * This may involve rounding or truncation. This implementation simply
|
|---|
| 122 | * casts the result of <code>doubleValue()</code> to <code>short</code>.
|
|---|
| 123 | *
|
|---|
| 124 | * @return the numeric value represented by this object after conversion
|
|---|
| 125 | * to type <code>short</code>.
|
|---|
| 126 | */
|
|---|
| 127 | public final short shortValue()
|
|---|
| 128 | {
|
|---|
| 129 | return (short) doubleValue();
|
|---|
| 130 | }
|
|---|
| 131 |
|
|---|
| 132 |
|
|---|
| 133 | /** Returns the denominator. */
|
|---|
| 134 | public final long getDenominator()
|
|---|
| 135 | {
|
|---|
| 136 | return this._denominator;
|
|---|
| 137 | }
|
|---|
| 138 |
|
|---|
| 139 | /** Returns the numerator. */
|
|---|
| 140 | public final long getNumerator()
|
|---|
| 141 | {
|
|---|
| 142 | return this._numerator;
|
|---|
| 143 | }
|
|---|
| 144 |
|
|---|
| 145 | /**
|
|---|
| 146 | * Returns the reciprocal value of this object as a new Rational.
|
|---|
| 147 | *
|
|---|
| 148 | * @return the reciprocal in a new object
|
|---|
| 149 | */
|
|---|
| 150 | @NotNull
|
|---|
| 151 | public Rational getReciprocal()
|
|---|
| 152 | {
|
|---|
| 153 | return new Rational(this._denominator, this._numerator);
|
|---|
| 154 | }
|
|---|
| 155 |
|
|---|
| 156 | /** Checks if this rational number is an Integer, either positive or negative. */
|
|---|
| 157 | public boolean isInteger()
|
|---|
| 158 | {
|
|---|
| 159 | return _denominator == 1 ||
|
|---|
| 160 | (_denominator != 0 && (_numerator % _denominator == 0)) ||
|
|---|
| 161 | (_denominator == 0 && _numerator == 0);
|
|---|
| 162 | }
|
|---|
| 163 |
|
|---|
| 164 | /**
|
|---|
| 165 | * Returns a string representation of the object of form <code>numerator/denominator</code>.
|
|---|
| 166 | *
|
|---|
| 167 | * @return a string representation of the object.
|
|---|
| 168 | */
|
|---|
| 169 | @NotNull
|
|---|
| 170 | public String toString()
|
|---|
| 171 | {
|
|---|
| 172 | return _numerator + "/" + _denominator;
|
|---|
| 173 | }
|
|---|
| 174 |
|
|---|
| 175 | /** Returns the simplest representation of this Rational's value possible. */
|
|---|
| 176 | @NotNull
|
|---|
| 177 | public String toSimpleString(boolean allowDecimal)
|
|---|
| 178 | {
|
|---|
| 179 | if (_denominator == 0 && _numerator != 0) {
|
|---|
| 180 | return toString();
|
|---|
| 181 | } else if (isInteger()) {
|
|---|
| 182 | return Integer.toString(intValue());
|
|---|
| 183 | } else if (_numerator != 1 && _denominator % _numerator == 0) {
|
|---|
| 184 | // common factor between denominator and numerator
|
|---|
| 185 | long newDenominator = _denominator / _numerator;
|
|---|
| 186 | return new Rational(1, newDenominator).toSimpleString(allowDecimal);
|
|---|
| 187 | } else {
|
|---|
| 188 | Rational simplifiedInstance = getSimplifiedInstance();
|
|---|
| 189 | if (allowDecimal) {
|
|---|
| 190 | String doubleString = Double.toString(simplifiedInstance.doubleValue());
|
|---|
| 191 | if (doubleString.length() < 5) {
|
|---|
| 192 | return doubleString;
|
|---|
| 193 | }
|
|---|
| 194 | }
|
|---|
| 195 | return simplifiedInstance.toString();
|
|---|
| 196 | }
|
|---|
| 197 | }
|
|---|
| 198 |
|
|---|
| 199 | /**
|
|---|
| 200 | * Decides whether a brute-force simplification calculation should be avoided
|
|---|
| 201 | * by comparing the maximum number of possible calculations with some threshold.
|
|---|
| 202 | *
|
|---|
| 203 | * @return true if the simplification should be performed, otherwise false
|
|---|
| 204 | */
|
|---|
| 205 | private boolean tooComplexForSimplification()
|
|---|
| 206 | {
|
|---|
| 207 | double maxPossibleCalculations = (((double) (Math.min(_denominator, _numerator) - 1) / 5d) + 2);
|
|---|
| 208 | final int maxSimplificationCalculations = 1000;
|
|---|
| 209 | return maxPossibleCalculations > maxSimplificationCalculations;
|
|---|
| 210 | }
|
|---|
| 211 |
|
|---|
| 212 | /**
|
|---|
| 213 | * Compares two <code>Rational</code> instances, returning true if they are mathematically
|
|---|
| 214 | * equivalent.
|
|---|
| 215 | *
|
|---|
| 216 | * @param obj the Rational to compare this instance to.
|
|---|
| 217 | * @return true if instances are mathematically equivalent, otherwise false. Will also
|
|---|
| 218 | * return false if <code>obj</code> is not an instance of <code>Rational</code>.
|
|---|
| 219 | */
|
|---|
| 220 | @Override
|
|---|
| 221 | public boolean equals(@Nullable Object obj)
|
|---|
| 222 | {
|
|---|
| 223 | if (obj==null || !(obj instanceof Rational))
|
|---|
| 224 | return false;
|
|---|
| 225 | Rational that = (Rational) obj;
|
|---|
| 226 | return this.doubleValue() == that.doubleValue();
|
|---|
| 227 | }
|
|---|
| 228 |
|
|---|
| 229 | @Override
|
|---|
| 230 | public int hashCode()
|
|---|
| 231 | {
|
|---|
| 232 | return (23 * (int)_denominator) + (int)_numerator;
|
|---|
| 233 | }
|
|---|
| 234 |
|
|---|
| 235 | /**
|
|---|
| 236 | * <p>
|
|---|
| 237 | * Simplifies the Rational number.</p>
|
|---|
| 238 | * <p>
|
|---|
| 239 | * Prime number series: 1, 2, 3, 5, 7, 9, 11, 13, 17</p>
|
|---|
| 240 | * <p>
|
|---|
| 241 | * To reduce a rational, need to see if both numerator and denominator are divisible
|
|---|
| 242 | * by a common factor. Using the prime number series in ascending order guarantees
|
|---|
| 243 | * the minimum number of checks required.</p>
|
|---|
| 244 | * <p>
|
|---|
| 245 | * However, generating the prime number series seems to be a hefty task. Perhaps
|
|---|
| 246 | * it's simpler to check if both d & n are divisible by all numbers from 2 ->
|
|---|
| 247 | * (Math.min(denominator, numerator) / 2). In doing this, one can check for 2
|
|---|
| 248 | * and 5 once, then ignore all even numbers, and all numbers ending in 0 or 5.
|
|---|
| 249 | * This leaves four numbers from every ten to check.</p>
|
|---|
| 250 | * <p>
|
|---|
| 251 | * Therefore, the max number of pairs of modulus divisions required will be:</p>
|
|---|
| 252 | * <code><pre>
|
|---|
| 253 | * 4 Math.min(denominator, numerator) - 1
|
|---|
| 254 | * -- * ------------------------------------ + 2
|
|---|
| 255 | * 10 2
|
|---|
| 256 | * <p/>
|
|---|
| 257 | * Math.min(denominator, numerator) - 1
|
|---|
| 258 | * = ------------------------------------ + 2
|
|---|
| 259 | * 5
|
|---|
| 260 | * </pre></code>
|
|---|
| 261 | *
|
|---|
| 262 | * @return a simplified instance, or if the Rational could not be simplified,
|
|---|
| 263 | * returns itself (unchanged)
|
|---|
| 264 | */
|
|---|
| 265 | @NotNull
|
|---|
| 266 | public Rational getSimplifiedInstance()
|
|---|
| 267 | {
|
|---|
| 268 | if (tooComplexForSimplification()) {
|
|---|
| 269 | return this;
|
|---|
| 270 | }
|
|---|
| 271 | for (int factor = 2; factor <= Math.min(_denominator, _numerator); factor++) {
|
|---|
| 272 | if ((factor % 2 == 0 && factor > 2) || (factor % 5 == 0 && factor > 5)) {
|
|---|
| 273 | continue;
|
|---|
| 274 | }
|
|---|
| 275 | if (_denominator % factor == 0 && _numerator % factor == 0) {
|
|---|
| 276 | // found a common factor
|
|---|
| 277 | return new Rational(_numerator / factor, _denominator / factor);
|
|---|
| 278 | }
|
|---|
| 279 | }
|
|---|
| 280 | return this;
|
|---|
| 281 | }
|
|---|
| 282 | }
|
|---|