1 | /*
|
---|
2 | * Copyright 2002-2016 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 | 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 | }
|
---|