1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.commons.math.fraction; 18 19 import java.math.BigInteger; 20 import org.apache.commons.math.util.MathUtils; 21 22 /** 23 * Representation of a rational number. 24 * 25 * @since 1.1 26 * @version $Revision: 620373 $ $Date: 2008-02-10 18:18:39 -0700 (Sun, 10 Feb 2008) $ 27 */ 28 public class Fraction extends Number implements Comparable { 29 30 /** A fraction representing "1 / 1". */ 31 public static final Fraction ONE = new Fraction(1, 1); 32 33 /** A fraction representing "0 / 1". */ 34 public static final Fraction ZERO = new Fraction(0, 1); 35 36 /** Serializable version identifier */ 37 private static final long serialVersionUID = -8958519416450949235L; 38 39 /** The denominator. */ 40 private final int denominator; 41 42 /** The numerator. */ 43 private final 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 FractionConversionException if the continued fraction failed to 49 * converge. 50 */ 51 public Fraction(double value) throws FractionConversionException { 52 this(value, 1.0e-5, 100); 53 } 54 55 /** 56 * Create a fraction given the double value and maximum error allowed. 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 FractionConversionException if the continued fraction failed to 69 * converge. 70 */ 71 public Fraction(double value, double epsilon, int maxIterations) 72 throws FractionConversionException 73 { 74 this(value, epsilon, Integer.MAX_VALUE, maxIterations); 75 } 76 77 /** 78 * Create a fraction given the double value and maximum denominator. 79 * <p> 80 * References: 81 * <ul> 82 * <li><a href="http://mathworld.wolfram.com/ContinuedFraction.html"> 83 * Continued Fraction</a> equations (11) and (22)-(26)</li> 84 * </ul> 85 * </p> 86 * @param value the double value to convert to a fraction. 87 * @param maxDenominator The maximum allowed value for denominator 88 * @throws FractionConversionException if the continued fraction failed to 89 * converge 90 */ 91 public Fraction(double value, int maxDenominator) 92 throws FractionConversionException 93 { 94 this(value, 0, maxDenominator, 100); 95 } 96 97 /** 98 * Create a fraction given the double value and either the maximum error 99 * allowed or the maximum number of denominator digits. 100 * <p> 101 * 102 * NOTE: This constructor is called with EITHER 103 * - a valid epsilon value and the maxDenominator set to Integer.MAX_VALUE 104 * (that way the maxDenominator has no effect). 105 * OR 106 * - a valid maxDenominator value and the epsilon value set to zero 107 * (that way epsilon only has effect if there is an exact match before 108 * the maxDenominator value is reached). 109 * </p><p> 110 * 111 * It has been done this way so that the same code can be (re)used for both 112 * scenarios. However this could be confusing to users if it were part of 113 * the public API and this constructor should therefore remain PRIVATE. 114 * </p> 115 * 116 * See JIRA issue ticket MATH-181 for more details: 117 * 118 * https://issues.apache.org/jira/browse/MATH-181 119 * 120 * @param value the double value to convert to a fraction. 121 * @param epsilon maximum error allowed. The resulting fraction is within 122 * <code>epsilon</code> of <code>value</code>, in absolute terms. 123 * @param maxDenominator maximum denominator value allowed. 124 * @param maxIterations maximum number of convergents 125 * @throws FractionConversionException if the continued fraction failed to 126 * converge. 127 */ 128 private Fraction(double value, double epsilon, int maxDenominator, int maxIterations) 129 throws FractionConversionException 130 { 131 long overflow = Integer.MAX_VALUE; 132 double r0 = value; 133 long a0 = (long)Math.floor(r0); 134 if (a0 > overflow) { 135 throw new FractionConversionException(value, a0, 1l); 136 } 137 138 // check for (almost) integer arguments, which should not go 139 // to iterations. 140 if (Math.abs(a0 - value) < epsilon) { 141 this.numerator = (int) a0; 142 this.denominator = 1; 143 return; 144 } 145 146 long p0 = 1; 147 long q0 = 0; 148 long p1 = a0; 149 long q1 = 1; 150 151 long p2 = 0; 152 long q2 = 1; 153 154 int n = 0; 155 boolean stop = false; 156 do { 157 ++n; 158 double r1 = 1.0 / (r0 - a0); 159 long a1 = (long)Math.floor(r1); 160 p2 = (a1 * p1) + p0; 161 q2 = (a1 * q1) + q0; 162 if ((p2 > overflow) || (q2 > overflow)) { 163 throw new FractionConversionException(value, p2, q2); 164 } 165 166 double convergent = (double)p2 / (double)q2; 167 if (n < maxIterations && Math.abs(convergent - value) > epsilon && q2 < maxDenominator) { 168 p0 = p1; 169 p1 = p2; 170 q0 = q1; 171 q1 = q2; 172 a0 = a1; 173 r0 = r1; 174 } else { 175 stop = true; 176 } 177 } while (!stop); 178 179 if (n >= maxIterations) { 180 throw new FractionConversionException(value, maxIterations); 181 } 182 183 if (q2 < maxDenominator) { 184 this.numerator = (int) p2; 185 this.denominator = (int) q2; 186 } else { 187 this.numerator = (int) p1; 188 this.denominator = (int) q1; 189 } 190 191 } 192 193 /** 194 * Create a fraction given the numerator and denominator. The fraction is 195 * reduced to lowest terms. 196 * @param num the numerator. 197 * @param den the denominator. 198 * @throws ArithmeticException if the denomiator is <code>zero</code> 199 */ 200 public Fraction(int num, int den) { 201 super(); 202 if (den == 0) { 203 throw new ArithmeticException("The denominator must not be zero"); 204 } 205 if (den < 0) { 206 if (num == Integer.MIN_VALUE || 207 den == Integer.MIN_VALUE) { 208 throw new ArithmeticException("overflow: can't negate"); 209 } 210 num = -num; 211 den = -den; 212 } 213 // reduce numerator and denominator by greatest common denominator. 214 int d = MathUtils.gcd(num, den); 215 if (d > 1) { 216 num /= d; 217 den /= d; 218 } 219 220 // move sign to numerator. 221 if (den < 0) { 222 num *= -1; 223 den *= -1; 224 } 225 this.numerator = num; 226 this.denominator = den; 227 } 228 229 /** 230 * Returns the absolute value of this fraction. 231 * @return the absolute value. 232 */ 233 public Fraction abs() { 234 Fraction ret; 235 if (numerator >= 0) { 236 ret = this; 237 } else { 238 ret = negate(); 239 } 240 return ret; 241 } 242 243 /** 244 * Compares this object to another based on size. 245 * @param object the object to compare to 246 * @return -1 if this is less than <tt>object</tt>, +1 if this is greater 247 * than <tt>object</tt>, 0 if they are equal. 248 */ 249 public int compareTo(Object object) { 250 int ret = 0; 251 252 if (this != object) { 253 Fraction other = (Fraction)object; 254 double first = doubleValue(); 255 double second = other.doubleValue(); 256 257 if (first < second) { 258 ret = -1; 259 } else if (first > second) { 260 ret = 1; 261 } 262 } 263 264 return ret; 265 } 266 267 /** 268 * Gets the fraction as a <tt>double</tt>. This calculates the fraction as 269 * the numerator divided by denominator. 270 * @return the fraction as a <tt>double</tt> 271 */ 272 public double doubleValue() { 273 return (double)numerator / (double)denominator; 274 } 275 276 /** 277 * Test for the equality of two fractions. If the lowest term 278 * numerator and denominators are the same for both fractions, the two 279 * fractions are considered to be equal. 280 * @param other fraction to test for equality to this fraction 281 * @return true if two fractions are equal, false if object is 282 * <tt>null</tt>, not an instance of {@link Fraction}, or not equal 283 * to this fraction instance. 284 */ 285 public boolean equals(Object other) { 286 boolean ret; 287 288 if (this == other) { 289 ret = true; 290 } else if (other == null) { 291 ret = false; 292 } else { 293 try { 294 // since fractions are always in lowest terms, numerators and 295 // denominators can be compared directly for equality. 296 Fraction rhs = (Fraction)other; 297 ret = (numerator == rhs.numerator) && 298 (denominator == rhs.denominator); 299 } catch (ClassCastException ex) { 300 // ignore exception 301 ret = false; 302 } 303 } 304 305 return ret; 306 } 307 308 /** 309 * Gets the fraction as a <tt>float</tt>. This calculates the fraction as 310 * the numerator divided by denominator. 311 * @return the fraction as a <tt>float</tt> 312 */ 313 public float floatValue() { 314 return (float)doubleValue(); 315 } 316 317 /** 318 * Access the denominator. 319 * @return the denominator. 320 */ 321 public int getDenominator() { 322 return denominator; 323 } 324 325 /** 326 * Access the numerator. 327 * @return the numerator. 328 */ 329 public int getNumerator() { 330 return numerator; 331 } 332 333 /** 334 * Gets a hashCode for the fraction. 335 * @return a hash code value for this object 336 */ 337 public int hashCode() { 338 return 37 * (37 * 17 + getNumerator()) + getDenominator(); 339 } 340 341 /** 342 * Gets the fraction as an <tt>int</tt>. This returns the whole number part 343 * of the fraction. 344 * @return the whole number fraction part 345 */ 346 public int intValue() { 347 return (int)doubleValue(); 348 } 349 350 /** 351 * Gets the fraction as a <tt>long</tt>. This returns the whole number part 352 * of the fraction. 353 * @return the whole number fraction part 354 */ 355 public long longValue() { 356 return (long)doubleValue(); 357 } 358 359 /** 360 * Return the additive inverse of this fraction. 361 * @return the negation of this fraction. 362 */ 363 public Fraction negate() { 364 if (numerator==Integer.MIN_VALUE) { 365 throw new ArithmeticException("overflow: too large to negate"); 366 } 367 return new Fraction(-numerator, denominator); 368 } 369 370 /** 371 * Return the multiplicative inverse of this fraction. 372 * @return the reciprocal fraction 373 */ 374 public Fraction reciprocal() { 375 return new Fraction(denominator, numerator); 376 } 377 378 /** 379 * <p>Adds the value of this fraction to another, returning the result in reduced form. 380 * The algorithm follows Knuth, 4.5.1.</p> 381 * 382 * @param fraction the fraction to add, must not be <code>null</code> 383 * @return a <code>Fraction</code> instance with the resulting values 384 * @throws IllegalArgumentException if the fraction is <code>null</code> 385 * @throws ArithmeticException if the resulting numerator or denominator exceeds 386 * <code>Integer.MAX_VALUE</code> 387 */ 388 public Fraction add(Fraction fraction) { 389 return addSub(fraction, true /* add */); 390 } 391 392 /** 393 * <p>Subtracts the value of another fraction from the value of this one, 394 * returning the result in reduced form.</p> 395 * 396 * @param fraction the fraction to subtract, must not be <code>null</code> 397 * @return a <code>Fraction</code> instance with the resulting values 398 * @throws IllegalArgumentException if the fraction is <code>null</code> 399 * @throws ArithmeticException if the resulting numerator or denominator 400 * cannot be represented in an <code>int</code>. 401 */ 402 public Fraction subtract(Fraction fraction) { 403 return addSub(fraction, false /* subtract */); 404 } 405 406 /** 407 * Implement add and subtract using algorithm described in Knuth 4.5.1. 408 * 409 * @param fraction the fraction to subtract, must not be <code>null</code> 410 * @param isAdd true to add, false to subtract 411 * @return a <code>Fraction</code> instance with the resulting values 412 * @throws IllegalArgumentException if the fraction is <code>null</code> 413 * @throws ArithmeticException if the resulting numerator or denominator 414 * cannot be represented in an <code>int</code>. 415 */ 416 private Fraction addSub(Fraction fraction, boolean isAdd) { 417 if (fraction == null) { 418 throw new IllegalArgumentException("The fraction must not be null"); 419 } 420 // zero is identity for addition. 421 if (numerator == 0) { 422 return isAdd ? fraction : fraction.negate(); 423 } 424 if (fraction.numerator == 0) { 425 return this; 426 } 427 // if denominators are randomly distributed, d1 will be 1 about 61% 428 // of the time. 429 int d1 = MathUtils.gcd(denominator, fraction.denominator); 430 if (d1==1) { 431 // result is ( (u*v' +/- u'v) / u'v') 432 int uvp = MathUtils.mulAndCheck(numerator, fraction.denominator); 433 int upv = MathUtils.mulAndCheck(fraction.numerator, denominator); 434 return new Fraction 435 (isAdd ? MathUtils.addAndCheck(uvp, upv) : 436 MathUtils.subAndCheck(uvp, upv), 437 MathUtils.mulAndCheck(denominator, fraction.denominator)); 438 } 439 // the quantity 't' requires 65 bits of precision; see knuth 4.5.1 440 // exercise 7. we're going to use a BigInteger. 441 // t = u(v'/d1) +/- v(u'/d1) 442 BigInteger uvp = BigInteger.valueOf(numerator) 443 .multiply(BigInteger.valueOf(fraction.denominator/d1)); 444 BigInteger upv = BigInteger.valueOf(fraction.numerator) 445 .multiply(BigInteger.valueOf(denominator/d1)); 446 BigInteger t = isAdd ? uvp.add(upv) : uvp.subtract(upv); 447 // but d2 doesn't need extra precision because 448 // d2 = gcd(t,d1) = gcd(t mod d1, d1) 449 int tmodd1 = t.mod(BigInteger.valueOf(d1)).intValue(); 450 int d2 = (tmodd1==0)?d1:MathUtils.gcd(tmodd1, d1); 451 452 // result is (t/d2) / (u'/d1)(v'/d2) 453 BigInteger w = t.divide(BigInteger.valueOf(d2)); 454 if (w.bitLength() > 31) { 455 throw new ArithmeticException 456 ("overflow: numerator too large after multiply"); 457 } 458 return new Fraction (w.intValue(), 459 MathUtils.mulAndCheck(denominator/d1, 460 fraction.denominator/d2)); 461 } 462 463 /** 464 * <p>Multiplies the value of this fraction by another, returning the 465 * result in reduced form.</p> 466 * 467 * @param fraction the fraction to multiply by, must not be <code>null</code> 468 * @return a <code>Fraction</code> instance with the resulting values 469 * @throws IllegalArgumentException if the fraction is <code>null</code> 470 * @throws ArithmeticException if the resulting numerator or denominator exceeds 471 * <code>Integer.MAX_VALUE</code> 472 */ 473 public Fraction multiply(Fraction fraction) { 474 if (fraction == null) { 475 throw new IllegalArgumentException("The fraction must not be null"); 476 } 477 if (numerator == 0 || fraction.numerator == 0) { 478 return ZERO; 479 } 480 // knuth 4.5.1 481 // make sure we don't overflow unless the result *must* overflow. 482 int d1 = MathUtils.gcd(numerator, fraction.denominator); 483 int d2 = MathUtils.gcd(fraction.numerator, denominator); 484 return getReducedFraction 485 (MathUtils.mulAndCheck(numerator/d1, fraction.numerator/d2), 486 MathUtils.mulAndCheck(denominator/d2, fraction.denominator/d1)); 487 } 488 489 /** 490 * <p>Divide the value of this fraction by another.</p> 491 * 492 * @param fraction the fraction to divide by, must not be <code>null</code> 493 * @return a <code>Fraction</code> instance with the resulting values 494 * @throws IllegalArgumentException if the fraction is <code>null</code> 495 * @throws ArithmeticException if the fraction to divide by is zero 496 * @throws ArithmeticException if the resulting numerator or denominator exceeds 497 * <code>Integer.MAX_VALUE</code> 498 */ 499 public Fraction divide(Fraction fraction) { 500 if (fraction == null) { 501 throw new IllegalArgumentException("The fraction must not be null"); 502 } 503 if (fraction.numerator == 0) { 504 throw new ArithmeticException("The fraction to divide by must not be zero"); 505 } 506 return multiply(fraction.reciprocal()); 507 } 508 509 /** 510 * <p>Creates a <code>Fraction</code> instance with the 2 parts 511 * of a fraction Y/Z.</p> 512 * 513 * <p>Any negative signs are resolved to be on the numerator.</p> 514 * 515 * @param numerator the numerator, for example the three in 'three sevenths' 516 * @param denominator the denominator, for example the seven in 'three sevenths' 517 * @return a new fraction instance, with the numerator and denominator reduced 518 * @throws ArithmeticException if the denominator is <code>zero</code> 519 */ 520 public static Fraction getReducedFraction(int numerator, int denominator) { 521 if (denominator == 0) { 522 throw new ArithmeticException("The denominator must not be zero"); 523 } 524 if (numerator==0) { 525 return ZERO; // normalize zero. 526 } 527 // allow 2^k/-2^31 as a valid fraction (where k>0) 528 if (denominator==Integer.MIN_VALUE && (numerator&1)==0) { 529 numerator/=2; denominator/=2; 530 } 531 if (denominator < 0) { 532 if (numerator==Integer.MIN_VALUE || 533 denominator==Integer.MIN_VALUE) { 534 throw new ArithmeticException("overflow: can't negate"); 535 } 536 numerator = -numerator; 537 denominator = -denominator; 538 } 539 // simplify fraction. 540 int gcd = MathUtils.gcd(numerator, denominator); 541 numerator /= gcd; 542 denominator /= gcd; 543 return new Fraction(numerator, denominator); 544 } 545 }