Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||||||
Fraction |
|
| 3.1818181818181817;3.182 |
1 | /* |
|
2 | * Copyright 2005 The Apache Software Foundation. |
|
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 | package org.apache.commons.math.fraction; |
|
17 | ||
18 | import java.math.BigInteger; |
|
19 | import org.apache.commons.math.ConvergenceException; |
|
20 | import org.apache.commons.math.util.MathUtils; |
|
21 | ||
22 | /** |
|
23 | * Representation of a rational number. |
|
24 | * |
|
25 | * @since 1.1 |
|
26 | * @version $Revision$ $Date: 2005-06-25 18:52:37 -0700 (Sat, 25 Jun 2005) $ |
|
27 | */ |
|
28 | public class Fraction extends Number implements Comparable { |
|
29 | ||
30 | /** A fraction representing "1 / 1". */ |
|
31 | 4 | public static final Fraction ONE = new Fraction(1, 1); |
32 | ||
33 | /** A fraction representing "0 / 1". */ |
|
34 | 4 | public static final Fraction ZERO = new Fraction(0, 1); |
35 | ||
36 | /** Serializable version identifier */ |
|
37 | static final long serialVersionUID = 65382027393090L; |
|
38 | ||
39 | /** The denominator. */ |
|
40 | private int denominator; |
|
41 | ||
42 | /** The numerator. */ |
|
43 | private int numerator; |
|
44 | ||
45 | /** |
|
46 | * Create a fraction given the double value. |
|
47 | * @param value the double value to convert to a fraction. |
|
48 | * @throws ConvergenceException if the continued fraction failed to |
|
49 | * converge. |
|
50 | */ |
|
51 | public Fraction(double value) throws ConvergenceException { |
|
52 | 22 | this(value, 1.0e-5, 100); |
53 | 22 | } |
54 | ||
55 | /** |
|
56 | * Create a fraction given the double value. |
|
57 | * <p> |
|
58 | * References: |
|
59 | * <ul> |
|
60 | * <li><a href="http://mathworld.wolfram.com/ContinuedFraction.html"> |
|
61 | * Continued Fraction</a> equations (11) and (22)-(26)</li> |
|
62 | * </ul> |
|
63 | * </p> |
|
64 | * @param value the double value to convert to a fraction. |
|
65 | * @param epsilon maximum error allowed. The resulting fraction is within |
|
66 | * <code>epsilon</code> of <code>value</code>, in absolute terms. |
|
67 | * @param maxIterations maximum number of convergents |
|
68 | * @throws ConvergenceException if the continued fraction failed to |
|
69 | * converge. |
|
70 | */ |
|
71 | public Fraction(double value, double epsilon, int maxIterations) |
|
72 | throws ConvergenceException |
|
73 | 22 | { |
74 | 22 | double r0 = value; |
75 | 22 | int a0 = (int)Math.floor(r0); |
76 | ||
77 | // check for (almost) integer arguments, which should not go |
|
78 | // to iterations. |
|
79 | 22 | if (Math.abs(a0 - value) < epsilon) { |
80 | 4 | this.numerator = a0; |
81 | 4 | this.denominator = 1; |
82 | 4 | return; |
83 | } |
|
84 | ||
85 | 18 | int p0 = 1; |
86 | 18 | int q0 = 0; |
87 | 18 | int p1 = a0; |
88 | 18 | int q1 = 1; |
89 | ||
90 | 18 | int p2 = 0; |
91 | 18 | int q2 = 1; |
92 | ||
93 | 18 | int n = 0; |
94 | 18 | boolean stop = false; |
95 | do { |
|
96 | 54 | ++n; |
97 | 54 | double r1 = 1.0 / (r0 - a0); |
98 | 54 | int a1 = (int)Math.floor(r1); |
99 | 54 | p2 = (a1 * p1) + p0; |
100 | 54 | q2 = (a1 * q1) + q0; |
101 | ||
102 | 54 | double convergent = (double)p2 / (double)q2; |
103 | 54 | if (n < maxIterations && Math.abs(convergent - value) > epsilon) { |
104 | 36 | p0 = p1; |
105 | 36 | p1 = p2; |
106 | 36 | q0 = q1; |
107 | 36 | q1 = q2; |
108 | 36 | a0 = a1; |
109 | 36 | r0 = r1; |
110 | } else { |
|
111 | 18 | stop = true; |
112 | } |
|
113 | 54 | } while (!stop); |
114 | ||
115 | 18 | if (n >= maxIterations) { |
116 | 0 | throw new ConvergenceException( |
117 | "Unable to convert double to fraction"); |
|
118 | } |
|
119 | ||
120 | 18 | this.numerator = p2; |
121 | 18 | this.denominator = q2; |
122 | 18 | reduce(); |
123 | 18 | } |
124 | ||
125 | /** |
|
126 | * Create a fraction given the numerator and denominator. The fraction is |
|
127 | * reduced to lowest terms. |
|
128 | * @param num the numerator. |
|
129 | * @param den the denominator. |
|
130 | * @throws ArithmeticException if the denomiator is <code>zero</code> |
|
131 | */ |
|
132 | public Fraction(int num, int den) { |
|
133 | 318 | super(); |
134 | 318 | if (den == 0) { |
135 | 2 | throw new ArithmeticException("The denominator must not be zero"); |
136 | } |
|
137 | 316 | if (den < 0) { |
138 | 24 | if (num == Integer.MIN_VALUE || |
139 | den == Integer.MIN_VALUE) { |
|
140 | 4 | throw new ArithmeticException("overflow: can't negate"); |
141 | } |
|
142 | 20 | num = -num; |
143 | 20 | den = -den; |
144 | } |
|
145 | 312 | this.numerator = num; |
146 | 312 | this.denominator = den; |
147 | 312 | reduce(); |
148 | 312 | } |
149 | ||
150 | /** |
|
151 | * Returns the absolute value of this fraction. |
|
152 | * @return the absolute value. |
|
153 | */ |
|
154 | public Fraction abs() { |
|
155 | Fraction ret; |
|
156 | 6 | if (numerator >= 0) { |
157 | 2 | ret = this; |
158 | } else { |
|
159 | 4 | ret = negate(); |
160 | } |
|
161 | 6 | return ret; |
162 | } |
|
163 | ||
164 | /** |
|
165 | * Compares this object to another based on size. |
|
166 | * @param object the object to compare to |
|
167 | * @return -1 if this is less than <tt>object</tt>, +1 if this is greater |
|
168 | * than <tt>object</tt>, 0 if they are equal. |
|
169 | */ |
|
170 | public int compareTo(Object object) { |
|
171 | 8 | int ret = 0; |
172 | ||
173 | 8 | if (this != object) { |
174 | 6 | Fraction other = (Fraction)object; |
175 | 6 | double first = doubleValue(); |
176 | 6 | double second = other.doubleValue(); |
177 | ||
178 | 6 | if (first < second) { |
179 | 2 | ret = -1; |
180 | 4 | } else if (first > second) { |
181 | 2 | ret = 1; |
182 | } |
|
183 | } |
|
184 | ||
185 | 8 | return ret; |
186 | } |
|
187 | ||
188 | /** |
|
189 | * Gets the fraction as a <tt>double</tt>. This calculates the fraction as |
|
190 | * the numerator divided by denominator. |
|
191 | * @return the fraction as a <tt>double</tt> |
|
192 | */ |
|
193 | public double doubleValue() { |
|
194 | 28 | return (double)numerator / (double)denominator; |
195 | } |
|
196 | ||
197 | /** |
|
198 | * Test for the equality of two fractions. If the lowest term |
|
199 | * numerator and denominators are the same for both fractions, the two |
|
200 | * fractions are considered to be equal. |
|
201 | * @param other fraction to test for equality to this fraction |
|
202 | * @return true if two fractions are equal, false if object is |
|
203 | * <tt>null</tt>, not an instance of {@link Fraction}, or not equal |
|
204 | * to this fraction instance. |
|
205 | */ |
|
206 | public boolean equals(Object other) { |
|
207 | boolean ret; |
|
208 | ||
209 | 16 | if (this == other) { |
210 | 4 | ret = true; |
211 | 12 | } else if (other == null) { |
212 | 2 | ret = false; |
213 | } else { |
|
214 | try { |
|
215 | // since fractions are always in lowest terms, numerators and |
|
216 | // denominators can be compared directly for equality. |
|
217 | 10 | Fraction rhs = (Fraction)other; |
218 | 8 | ret = (numerator == rhs.numerator) && |
219 | (denominator == rhs.denominator); |
|
220 | 2 | } catch (ClassCastException ex) { |
221 | // ignore exception |
|
222 | 2 | ret = false; |
223 | 8 | } |
224 | } |
|
225 | ||
226 | 16 | return ret; |
227 | } |
|
228 | ||
229 | /** |
|
230 | * Gets the fraction as a <tt>float</tt>. This calculates the fraction as |
|
231 | * the numerator divided by denominator. |
|
232 | * @return the fraction as a <tt>float</tt> |
|
233 | */ |
|
234 | public float floatValue() { |
|
235 | 4 | return (float)doubleValue(); |
236 | } |
|
237 | ||
238 | /** |
|
239 | * Access the denominator. |
|
240 | * @return the denominator. |
|
241 | */ |
|
242 | public int getDenominator() { |
|
243 | 162 | return denominator; |
244 | } |
|
245 | ||
246 | /** |
|
247 | * Access the numerator. |
|
248 | * @return the numerator. |
|
249 | */ |
|
250 | public int getNumerator() { |
|
251 | 166 | return numerator; |
252 | } |
|
253 | ||
254 | /** |
|
255 | * Gets a hashCode for the fraction. |
|
256 | * @return a hash code value for this object |
|
257 | */ |
|
258 | public int hashCode() { |
|
259 | 6 | return 37 * (37 * 17 + getNumerator()) + getDenominator(); |
260 | } |
|
261 | ||
262 | /** |
|
263 | * Gets the fraction as an <tt>int</tt>. This returns the whole number part |
|
264 | * of the fraction. |
|
265 | * @return the whole number fraction part |
|
266 | */ |
|
267 | public int intValue() { |
|
268 | 4 | return (int)doubleValue(); |
269 | } |
|
270 | ||
271 | /** |
|
272 | * Gets the fraction as a <tt>long</tt>. This returns the whole number part |
|
273 | * of the fraction. |
|
274 | * @return the whole number fraction part |
|
275 | */ |
|
276 | public long longValue() { |
|
277 | 4 | return (long)doubleValue(); |
278 | } |
|
279 | ||
280 | /** |
|
281 | * Return the additive inverse of this fraction. |
|
282 | * @return the negation of this fraction. |
|
283 | */ |
|
284 | public Fraction negate() { |
|
285 | 16 | if (numerator==Integer.MIN_VALUE) { |
286 | 2 | throw new ArithmeticException("overflow: too large to negate"); |
287 | } |
|
288 | 14 | return new Fraction(-numerator, denominator); |
289 | } |
|
290 | ||
291 | /** |
|
292 | * Return the multiplicative inverse of this fraction. |
|
293 | * @return the reciprocal fraction |
|
294 | */ |
|
295 | public Fraction reciprocal() { |
|
296 | 34 | return new Fraction(denominator, numerator); |
297 | } |
|
298 | ||
299 | /** |
|
300 | * <p>Adds the value of this fraction to another, returning the result in reduced form. |
|
301 | * The algorithm follows Knuth, 4.5.1.</p> |
|
302 | * |
|
303 | * @param fraction the fraction to add, must not be <code>null</code> |
|
304 | * @return a <code>Fraction</code> instance with the resulting values |
|
305 | * @throws IllegalArgumentException if the fraction is <code>null</code> |
|
306 | * @throws ArithmeticException if the resulting numerator or denominator exceeds |
|
307 | * <code>Integer.MAX_VALUE</code> |
|
308 | */ |
|
309 | public Fraction add(Fraction fraction) { |
|
310 | 30 | return addSub(fraction, true /* add */); |
311 | } |
|
312 | ||
313 | /** |
|
314 | * <p>Subtracts the value of another fraction from the value of this one, |
|
315 | * returning the result in reduced form.</p> |
|
316 | * |
|
317 | * @param fraction the fraction to subtract, must not be <code>null</code> |
|
318 | * @return a <code>Fraction</code> instance with the resulting values |
|
319 | * @throws IllegalArgumentException if the fraction is <code>null</code> |
|
320 | * @throws ArithmeticException if the resulting numerator or denominator |
|
321 | * cannot be represented in an <code>int</code>. |
|
322 | */ |
|
323 | public Fraction subtract(Fraction fraction) { |
|
324 | 26 | return addSub(fraction, false /* subtract */); |
325 | } |
|
326 | ||
327 | /** |
|
328 | * Implement add and subtract using algorithm described in Knuth 4.5.1. |
|
329 | * |
|
330 | * @param fraction the fraction to subtract, must not be <code>null</code> |
|
331 | * @param isAdd true to add, false to subtract |
|
332 | * @return a <code>Fraction</code> instance with the resulting values |
|
333 | * @throws IllegalArgumentException if the fraction is <code>null</code> |
|
334 | * @throws ArithmeticException if the resulting numerator or denominator |
|
335 | * cannot be represented in an <code>int</code>. |
|
336 | */ |
|
337 | private Fraction addSub(Fraction fraction, boolean isAdd) { |
|
338 | 56 | if (fraction == null) { |
339 | 4 | throw new IllegalArgumentException("The fraction must not be null"); |
340 | } |
|
341 | // zero is identity for addition. |
|
342 | 52 | if (numerator == 0) { |
343 | 0 | return isAdd ? fraction : fraction.negate(); |
344 | } |
|
345 | 52 | if (fraction.numerator == 0) { |
346 | 0 | return this; |
347 | } |
|
348 | // if denominators are randomly distributed, d1 will be 1 about 61% |
|
349 | // of the time. |
|
350 | 52 | int d1 = MathUtils.gcd(denominator, fraction.denominator); |
351 | 52 | if (d1==1) { |
352 | // result is ( (u*v' +/- u'v) / u'v') |
|
353 | 30 | int uvp = MathUtils.mulAndCheck(numerator, fraction.denominator); |
354 | 30 | int upv = MathUtils.mulAndCheck(fraction.numerator, denominator); |
355 | 30 | return new Fraction |
356 | (isAdd ? MathUtils.addAndCheck(uvp, upv) : |
|
357 | MathUtils.subAndCheck(uvp, upv), |
|
358 | MathUtils.mulAndCheck(denominator, fraction.denominator)); |
|
359 | } |
|
360 | // the quantity 't' requires 65 bits of precision; see knuth 4.5.1 |
|
361 | // exercise 7. we're going to use a BigInteger. |
|
362 | // t = u(v'/d1) +/- v(u'/d1) |
|
363 | 22 | BigInteger uvp = BigInteger.valueOf(numerator) |
364 | .multiply(BigInteger.valueOf(fraction.denominator/d1)); |
|
365 | 22 | BigInteger upv = BigInteger.valueOf(fraction.numerator) |
366 | .multiply(BigInteger.valueOf(denominator/d1)); |
|
367 | 22 | BigInteger t = isAdd ? uvp.add(upv) : uvp.subtract(upv); |
368 | // but d2 doesn't need extra precision because |
|
369 | // d2 = gcd(t,d1) = gcd(t mod d1, d1) |
|
370 | 22 | int tmodd1 = t.mod(BigInteger.valueOf(d1)).intValue(); |
371 | 22 | int d2 = (tmodd1==0)?d1:MathUtils.gcd(tmodd1, d1); |
372 | ||
373 | // result is (t/d2) / (u'/d1)(v'/d2) |
|
374 | 22 | BigInteger w = t.divide(BigInteger.valueOf(d2)); |
375 | 22 | if (w.bitLength() > 31) { |
376 | 4 | throw new ArithmeticException |
377 | ("overflow: numerator too large after multiply"); |
|
378 | } |
|
379 | 18 | return new Fraction (w.intValue(), |
380 | MathUtils.mulAndCheck(denominator/d1, |
|
381 | fraction.denominator/d2)); |
|
382 | } |
|
383 | ||
384 | /** |
|
385 | * <p>Multiplies the value of this fraction by another, returning the |
|
386 | * result in reduced form.</p> |
|
387 | * |
|
388 | * @param fraction the fraction to multiply by, must not be <code>null</code> |
|
389 | * @return a <code>Fraction</code> instance with the resulting values |
|
390 | * @throws IllegalArgumentException if the fraction is <code>null</code> |
|
391 | * @throws ArithmeticException if the resulting numerator or denominator exceeds |
|
392 | * <code>Integer.MAX_VALUE</code> |
|
393 | */ |
|
394 | public Fraction multiply(Fraction fraction) { |
|
395 | 32 | if (fraction == null) { |
396 | 2 | throw new IllegalArgumentException("The fraction must not be null"); |
397 | } |
|
398 | 30 | if (numerator == 0 || fraction.numerator == 0) { |
399 | 2 | return ZERO; |
400 | } |
|
401 | // knuth 4.5.1 |
|
402 | // make sure we don't overflow unless the result *must* overflow. |
|
403 | 28 | int d1 = MathUtils.gcd(numerator, fraction.denominator); |
404 | 28 | int d2 = MathUtils.gcd(fraction.numerator, denominator); |
405 | 28 | return getReducedFraction |
406 | (MathUtils.mulAndCheck(numerator/d1, fraction.numerator/d2), |
|
407 | MathUtils.mulAndCheck(denominator/d2, fraction.denominator/d1)); |
|
408 | } |
|
409 | ||
410 | /** |
|
411 | * <p>Divide the value of this fraction by another.</p> |
|
412 | * |
|
413 | * @param fraction the fraction to divide by, must not be <code>null</code> |
|
414 | * @return a <code>Fraction</code> instance with the resulting values |
|
415 | * @throws IllegalArgumentException if the fraction is <code>null</code> |
|
416 | * @throws ArithmeticException if the fraction to divide by is zero |
|
417 | * @throws ArithmeticException if the resulting numerator or denominator exceeds |
|
418 | * <code>Integer.MAX_VALUE</code> |
|
419 | */ |
|
420 | public Fraction divide(Fraction fraction) { |
|
421 | 24 | if (fraction == null) { |
422 | 2 | throw new IllegalArgumentException("The fraction must not be null"); |
423 | } |
|
424 | 22 | if (fraction.numerator == 0) { |
425 | 2 | throw new ArithmeticException("The fraction to divide by must not be zero"); |
426 | } |
|
427 | 20 | return multiply(fraction.reciprocal()); |
428 | } |
|
429 | ||
430 | /** |
|
431 | * <p>Creates a <code>Fraction</code> instance with the 2 parts |
|
432 | * of a fraction Y/Z.</p> |
|
433 | * |
|
434 | * <p>Any negative signs are resolved to be on the numerator.</p> |
|
435 | * |
|
436 | * @param numerator the numerator, for example the three in 'three sevenths' |
|
437 | * @param denominator the denominator, for example the seven in 'three sevenths' |
|
438 | * @return a new fraction instance, with the numerator and denominator reduced |
|
439 | * @throws ArithmeticException if the denominator is <code>zero</code> |
|
440 | */ |
|
441 | public static Fraction getReducedFraction(int numerator, int denominator) { |
|
442 | 34 | if (denominator == 0) { |
443 | 2 | throw new ArithmeticException("The denominator must not be zero"); |
444 | } |
|
445 | 32 | if (numerator==0) { |
446 | 2 | return ZERO; // normalize zero. |
447 | } |
|
448 | // allow 2^k/-2^31 as a valid fraction (where k>0) |
|
449 | 30 | if (denominator==Integer.MIN_VALUE && (numerator&1)==0) { |
450 | 2 | numerator/=2; denominator/=2; |
451 | } |
|
452 | 30 | if (denominator < 0) { |
453 | 4 | if (numerator==Integer.MIN_VALUE || |
454 | denominator==Integer.MIN_VALUE) { |
|
455 | 0 | throw new ArithmeticException("overflow: can't negate"); |
456 | } |
|
457 | 4 | numerator = -numerator; |
458 | 4 | denominator = -denominator; |
459 | } |
|
460 | // simplify fraction. |
|
461 | 30 | int gcd = MathUtils.gcd(numerator, denominator); |
462 | 30 | numerator /= gcd; |
463 | 30 | denominator /= gcd; |
464 | 30 | return new Fraction(numerator, denominator); |
465 | } |
|
466 | ||
467 | /** |
|
468 | * Reduce this fraction to lowest terms. This is accomplished by dividing |
|
469 | * both numerator and denominator by their greatest common divisor. |
|
470 | */ |
|
471 | private void reduce() { |
|
472 | // reduce numerator and denominator by greatest common denominator. |
|
473 | 330 | int d = MathUtils.gcd(numerator, denominator); |
474 | 330 | if (d > 1) { |
475 | 22 | numerator /= d; |
476 | 22 | denominator /= d; |
477 | } |
|
478 | ||
479 | // move sign to numerator. |
|
480 | 330 | if (denominator < 0) { |
481 | 0 | numerator *= -1; |
482 | 0 | denominator *= -1; |
483 | } |
|
484 | 330 | } |
485 | } |