1 16 package org.apache.commons.lang.math; 17 18 import java.io.Serializable ; 19 import java.math.BigInteger ; 20 21 36 public final class Fraction extends Number implements Serializable , Comparable { 37 38 39 private static final long serialVersionUID = 65382027393090L; 40 41 44 public static final Fraction ZERO = new Fraction(0, 1); 45 48 public static final Fraction ONE = new Fraction(1, 1); 49 52 public static final Fraction ONE_HALF = new Fraction(1, 2); 53 56 public static final Fraction ONE_THIRD = new Fraction(1, 3); 57 60 public static final Fraction TWO_THIRDS = new Fraction(2, 3); 61 64 public static final Fraction ONE_QUARTER = new Fraction(1, 4); 65 68 public static final Fraction TWO_QUARTERS = new Fraction(2, 4); 69 72 public static final Fraction THREE_QUARTERS = new Fraction(3, 4); 73 76 public static final Fraction ONE_FIFTH = new Fraction(1, 5); 77 80 public static final Fraction TWO_FIFTHS = new Fraction(2, 5); 81 84 public static final Fraction THREE_FIFTHS = new Fraction(3, 5); 85 88 public static final Fraction FOUR_FIFTHS = new Fraction(4, 5); 89 90 91 94 private final int numerator; 95 98 private final int denominator; 99 100 103 private transient int hashCode = 0; 104 107 private transient String toString = null; 108 111 private transient String toProperString = null; 112 113 120 private Fraction(int numerator, int denominator) { 121 super(); 122 this.numerator = numerator; 123 this.denominator = denominator; 124 } 125 126 137 public static Fraction getFraction(int numerator, int denominator) { 138 if (denominator == 0) { 139 throw new ArithmeticException ("The denominator must not be zero"); 140 } 141 if (denominator < 0) { 142 if (numerator==Integer.MIN_VALUE || 143 denominator==Integer.MIN_VALUE) { 144 throw new ArithmeticException ("overflow: can't negate"); 145 } 146 numerator = -numerator; 147 denominator = -denominator; 148 } 149 return new Fraction(numerator, denominator); 150 } 151 152 168 public static Fraction getFraction(int whole, int numerator, int denominator) { 169 if (denominator == 0) { 170 throw new ArithmeticException ("The denominator must not be zero"); 171 } 172 if (denominator < 0) { 173 throw new ArithmeticException ("The denominator must not be negative"); 174 } 175 if (numerator < 0) { 176 throw new ArithmeticException ("The numerator must not be negative"); 177 } 178 long numeratorValue; 179 if (whole < 0) { 180 numeratorValue = whole * (long)denominator - numerator; 181 } else { 182 numeratorValue = whole * (long)denominator + numerator; 183 } 184 if (numeratorValue < Integer.MIN_VALUE || 185 numeratorValue > Integer.MAX_VALUE) { 186 throw new ArithmeticException ("Numerator too large to represent as an Integer."); 187 } 188 return new Fraction((int) numeratorValue, denominator); 189 } 190 191 202 public static Fraction getReducedFraction(int numerator, int denominator) { 203 if (denominator == 0) { 204 throw new ArithmeticException ("The denominator must not be zero"); 205 } 206 if (numerator==0) { 207 return ZERO; } 209 if (denominator==Integer.MIN_VALUE && (numerator&1)==0) { 211 numerator/=2; denominator/=2; 212 } 213 if (denominator < 0) { 214 if (numerator==Integer.MIN_VALUE || 215 denominator==Integer.MIN_VALUE) { 216 throw new ArithmeticException ("overflow: can't negate"); 217 } 218 numerator = -numerator; 219 denominator = -denominator; 220 } 221 int gcd = greatestCommonDivisor(numerator, denominator); 223 numerator /= gcd; 224 denominator /= gcd; 225 return new Fraction(numerator, denominator); 226 } 227 228 242 public static Fraction getFraction(double value) { 243 int sign = (value < 0 ? -1 : 1); 244 value = Math.abs(value); 245 if (value > Integer.MAX_VALUE || Double.isNaN(value)) { 246 throw new ArithmeticException 247 ("The value must not be greater than Integer.MAX_VALUE or NaN"); 248 } 249 int wholeNumber = (int) value; 250 value -= wholeNumber; 251 252 int numer0 = 0; int denom0 = 1; int numer1 = 1; int denom1 = 0; int numer2 = 0; int denom2 = 0; int a1 = (int) value; 259 int a2 = 0; 260 double x1 = 1; 261 double x2 = 0; 262 double y1 = value - a1; 263 double y2 = 0; 264 double delta1, delta2 = Double.MAX_VALUE; 265 double fraction; 266 int i = 1; 267 do { 269 delta1 = delta2; 270 a2 = (int) (x1 / y1); 271 x2 = y1; 272 y2 = x1 - a2 * y1; 273 numer2 = a1 * numer1 + numer0; 274 denom2 = a1 * denom1 + denom0; 275 fraction = (double) numer2 / (double) denom2; 276 delta2 = Math.abs(value - fraction); 277 a1 = a2; 279 x1 = x2; 280 y1 = y2; 281 numer0 = numer1; 282 denom0 = denom1; 283 numer1 = numer2; 284 denom1 = denom2; 285 i++; 286 } while ((delta1 > delta2) && (denom2 <= 10000) && (denom2 > 0) && (i < 25)); 288 if (i == 25) { 289 throw new ArithmeticException ("Unable to convert double to fraction"); 290 } 291 return getReducedFraction((numer0 + wholeNumber * denom0) * sign, denom0); 292 } 293 294 312 public static Fraction getFraction(String str) { 313 if (str == null) { 314 throw new IllegalArgumentException ("The string must not be null"); 315 } 316 int pos = str.indexOf('.'); 318 if (pos >= 0) { 319 return getFraction(Double.parseDouble(str)); 320 } 321 322 pos = str.indexOf(' '); 324 if (pos > 0) { 325 int whole = Integer.parseInt(str.substring(0, pos)); 326 str = str.substring(pos + 1); 327 pos = str.indexOf('/'); 328 if (pos < 0) { 329 throw new NumberFormatException ("The fraction could not be parsed as the format X Y/Z"); 330 } else { 331 int numer = Integer.parseInt(str.substring(0, pos)); 332 int denom = Integer.parseInt(str.substring(pos + 1)); 333 return getFraction(whole, numer, denom); 334 } 335 } 336 337 pos = str.indexOf('/'); 339 if (pos < 0) { 340 return getFraction(Integer.parseInt(str), 1); 342 } else { 343 int numer = Integer.parseInt(str.substring(0, pos)); 344 int denom = Integer.parseInt(str.substring(pos + 1)); 345 return getFraction(numer, denom); 346 } 347 } 348 349 352 360 public int getNumerator() { 361 return numerator; 362 } 363 364 369 public int getDenominator() { 370 return denominator; 371 } 372 373 384 public int getProperNumerator() { 385 return Math.abs(numerator % denominator); 386 } 387 388 399 public int getProperWhole() { 400 return numerator / denominator; 401 } 402 403 406 412 public int intValue() { 413 return numerator / denominator; 414 } 415 416 422 public long longValue() { 423 return (long) numerator / denominator; 424 } 425 426 432 public float floatValue() { 433 return ((float) numerator) / ((float) denominator); 434 } 435 436 442 public double doubleValue() { 443 return ((double) numerator) / ((double) denominator); 444 } 445 446 449 455 public Fraction reduce() { 456 int gcd = greatestCommonDivisor(Math.abs(numerator), denominator); 457 return Fraction.getFraction(numerator / gcd, denominator / gcd); 458 } 459 460 469 public Fraction invert() { 470 if (numerator == 0) { 471 throw new ArithmeticException ("Unable to invert zero."); 472 } 473 if (numerator==Integer.MIN_VALUE) { 474 throw new ArithmeticException ("overflow: can't negate numerator"); 475 } 476 if (numerator<0) { 477 return new Fraction(-denominator, -numerator); 478 } else { 479 return new Fraction(denominator, numerator); 480 } 481 } 482 483 490 public Fraction negate() { 491 if (numerator==Integer.MIN_VALUE) { 493 throw new ArithmeticException ("overflow: too large to negate"); 494 } 495 return new Fraction(-numerator, denominator); 496 } 497 498 507 public Fraction abs() { 508 if (numerator >= 0) { 509 return this; 510 } 511 return negate(); 512 } 513 514 526 public Fraction pow(int power) { 527 if (power == 1) { 528 return this; 529 } else if (power == 0) { 530 return ONE; 531 } else if (power < 0) { 532 if (power==Integer.MIN_VALUE) { return this.invert().pow(2).pow(-(power/2)); 534 } 535 return this.invert().pow(-power); 536 } else { 537 Fraction f = this.multiplyBy(this); 538 if ((power % 2) == 0) { return f.pow(power/2); 540 } else { return f.pow(power/2).multiplyBy(this); 542 } 543 } 544 } 545 546 556 private static int greatestCommonDivisor(int u, int v) { 557 562 if (u>0) { u=-u; } if (v>0) { v=-v; } int k=0; 566 while ((u&1)==0 && (v&1)==0 && k<31) { u/=2; v/=2; k++; } 569 if (k==31) { 570 throw new ArithmeticException ("overflow: gcd is 2^31"); 571 } 572 int t = ((u&1)==1) ? v : -(u/2); 575 do { 578 579 while ((t&1)==0) { t/=2; } 583 if (t>0) { 585 u = -t; 586 } else { 587 v = t; 588 } 589 t = (v - u)/2; 591 } while (t!=0); 594 return -u*(1<<k); } 596 597 600 609 private static int mulAndCheck(int x, int y) { 610 long m = ((long)x)*((long)y); 611 if (m < Integer.MIN_VALUE || 612 m > Integer.MAX_VALUE) { 613 throw new ArithmeticException ("overflow: mul"); 614 } 615 return (int)m; 616 } 617 618 627 private static int mulPosAndCheck(int x, int y) { 628 629 long m = ((long)x)*((long)y); 630 if (m > Integer.MAX_VALUE) { 631 throw new ArithmeticException ("overflow: mulPos"); 632 } 633 return (int)m; 634 } 635 636 645 private static int addAndCheck(int x, int y) { 646 long s = (long)x+(long)y; 647 if (s < Integer.MIN_VALUE || 648 s > Integer.MAX_VALUE) { 649 throw new ArithmeticException ("overflow: add"); 650 } 651 return (int)s; 652 } 653 654 663 private static int subAndCheck(int x, int y) { 664 long s = (long)x-(long)y; 665 if (s < Integer.MIN_VALUE || 666 s > Integer.MAX_VALUE) { 667 throw new ArithmeticException ("overflow: add"); 668 } 669 return (int)s; 670 } 671 672 682 public Fraction add(Fraction fraction) { 683 return addSub(fraction, true ); 684 } 685 686 696 public Fraction subtract(Fraction fraction) { 697 return addSub(fraction, false ); 698 } 699 700 710 private Fraction addSub(Fraction fraction, boolean isAdd) { 711 if (fraction == null) { 712 throw new IllegalArgumentException ("The fraction must not be null"); 713 } 714 if (numerator == 0) { 716 return isAdd ? fraction : fraction.negate(); 717 } 718 if (fraction.numerator == 0) { 719 return this; 720 } 721 int d1 = greatestCommonDivisor(denominator, fraction.denominator); 724 if (d1==1) { 725 int uvp = mulAndCheck(numerator, fraction.denominator); 727 int upv = mulAndCheck(fraction.numerator, denominator); 728 return new Fraction 729 (isAdd ? addAndCheck(uvp, upv) : subAndCheck(uvp, upv), 730 mulPosAndCheck(denominator, fraction.denominator)); 731 } 732 BigInteger uvp = BigInteger.valueOf(numerator) 736 .multiply(BigInteger.valueOf(fraction.denominator/d1)); 737 BigInteger upv = BigInteger.valueOf(fraction.numerator) 738 .multiply(BigInteger.valueOf(denominator/d1)); 739 BigInteger t = isAdd ? uvp.add(upv) : uvp.subtract(upv); 740 int tmodd1 = t.mod(BigInteger.valueOf(d1)).intValue(); 743 int d2 = (tmodd1==0)?d1:greatestCommonDivisor(tmodd1, d1); 744 745 BigInteger w = t.divide(BigInteger.valueOf(d2)); 747 if (w.bitLength() > 31) { 748 throw new ArithmeticException 749 ("overflow: numerator too large after multiply"); 750 } 751 return new Fraction 752 (w.intValue(), 753 mulPosAndCheck(denominator/d1, fraction.denominator/d2)); 754 } 755 756 766 public Fraction multiplyBy(Fraction fraction) { 767 if (fraction == null) { 768 throw new IllegalArgumentException ("The fraction must not be null"); 769 } 770 if (numerator == 0 || fraction.numerator == 0) { 771 return ZERO; 772 } 773 int d1 = greatestCommonDivisor(numerator, fraction.denominator); 776 int d2 = greatestCommonDivisor(fraction.numerator, denominator); 777 return getReducedFraction 778 (mulAndCheck(numerator/d1, fraction.numerator/d2), 779 mulPosAndCheck(denominator/d2, fraction.denominator/d1)); 780 } 781 782 792 public Fraction divideBy(Fraction fraction) { 793 if (fraction == null) { 794 throw new IllegalArgumentException ("The fraction must not be null"); 795 } 796 if (fraction.numerator == 0) { 797 throw new ArithmeticException ("The fraction to divide by must not be zero"); 798 } 799 return multiplyBy(fraction.invert()); 800 } 801 802 805 813 public boolean equals(Object obj) { 814 if (obj == this) { 815 return true; 816 } 817 if (obj instanceof Fraction == false) { 818 return false; 819 } 820 Fraction other = (Fraction) obj; 821 return (getNumerator() == other.getNumerator() && 822 getDenominator() == other.getDenominator()); 823 } 824 825 830 public int hashCode() { 831 if (hashCode == 0) { 832 hashCode = 37 * (37 * 17 + getNumerator()) + getDenominator(); 834 } 835 return hashCode; 836 } 837 838 846 public int compareTo(Object object) { 847 Fraction other = (Fraction) object; 848 if (this==other) { 849 return 0; 850 } 851 if (numerator == other.numerator && denominator == other.denominator) { 852 return 0; 853 } 854 855 long first = (long) numerator * (long) other.denominator; 857 long second = (long) other.numerator * (long) denominator; 858 if (first == second) { 859 return 0; 860 } else if (first < second) { 861 return -1; 862 } else { 863 return 1; 864 } 865 } 866 867 874 public String toString() { 875 if (toString == null) { 876 toString = new StringBuffer (32) 877 .append(getNumerator()) 878 .append('/') 879 .append(getDenominator()).toString(); 880 } 881 return toString; 882 } 883 884 893 public String toProperString() { 894 if (toProperString == null) { 895 if (numerator == 0) { 896 toProperString = "0"; 897 } else if (numerator == denominator) { 898 toProperString = "1"; 899 } else if ((numerator>0?-numerator:numerator) < -denominator) { 900 int properNumerator = getProperNumerator(); 905 if (properNumerator == 0) { 906 toProperString = Integer.toString(getProperWhole()); 907 } else { 908 toProperString = new StringBuffer (32) 909 .append(getProperWhole()).append(' ') 910 .append(properNumerator).append('/') 911 .append(getDenominator()).toString(); 912 } 913 } else { 914 toProperString = new StringBuffer (32) 915 .append(getNumerator()).append('/') 916 .append(getDenominator()).toString(); 917 } 918 } 919 return toProperString; 920 } 921 } 922 | Popular Tags |