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