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 | }
|
---|