📄 fraction.java
字号:
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.apache.commons.math.fraction;import java.math.BigInteger;import org.apache.commons.math.util.MathUtils;/** * Representation of a rational number. * * @since 1.1 * @version $Revision: 620373 $ $Date: 2008-02-10 18:18:39 -0700 (Sun, 10 Feb 2008) $ */public class Fraction extends Number implements Comparable { /** A fraction representing "1 / 1". */ public static final Fraction ONE = new Fraction(1, 1); /** A fraction representing "0 / 1". */ public static final Fraction ZERO = new Fraction(0, 1); /** Serializable version identifier */ private static final long serialVersionUID = -8958519416450949235L; /** The denominator. */ private final int denominator; /** The numerator. */ private final int numerator; /** * Create a fraction given the double value. * @param value the double value to convert to a fraction. * @throws FractionConversionException if the continued fraction failed to * converge. */ public Fraction(double value) throws FractionConversionException { this(value, 1.0e-5, 100); } /** * Create a fraction given the double value and maximum error allowed. * <p> * References: * <ul> * <li><a href="http://mathworld.wolfram.com/ContinuedFraction.html"> * Continued Fraction</a> equations (11) and (22)-(26)</li> * </ul> * </p> * @param value the double value to convert to a fraction. * @param epsilon maximum error allowed. The resulting fraction is within * <code>epsilon</code> of <code>value</code>, in absolute terms. * @param maxIterations maximum number of convergents * @throws FractionConversionException if the continued fraction failed to * converge. */ public Fraction(double value, double epsilon, int maxIterations) throws FractionConversionException { this(value, epsilon, Integer.MAX_VALUE, maxIterations); } /** * Create a fraction given the double value and maximum denominator. * <p> * References: * <ul> * <li><a href="http://mathworld.wolfram.com/ContinuedFraction.html"> * Continued Fraction</a> equations (11) and (22)-(26)</li> * </ul> * </p> * @param value the double value to convert to a fraction. * @param maxDenominator The maximum allowed value for denominator * @throws FractionConversionException if the continued fraction failed to * converge */ public Fraction(double value, int maxDenominator) throws FractionConversionException { this(value, 0, maxDenominator, 100); } /** * Create a fraction given the double value and either the maximum error * allowed or the maximum number of denominator digits. * <p> * * NOTE: This constructor is called with EITHER * - a valid epsilon value and the maxDenominator set to Integer.MAX_VALUE * (that way the maxDenominator has no effect). * OR * - a valid maxDenominator value and the epsilon value set to zero * (that way epsilon only has effect if there is an exact match before * the maxDenominator value is reached). * </p><p> * * It has been done this way so that the same code can be (re)used for both * scenarios. However this could be confusing to users if it were part of * the public API and this constructor should therefore remain PRIVATE. * </p> * * See JIRA issue ticket MATH-181 for more details: * * https://issues.apache.org/jira/browse/MATH-181 * * @param value the double value to convert to a fraction. * @param epsilon maximum error allowed. The resulting fraction is within * <code>epsilon</code> of <code>value</code>, in absolute terms. * @param maxDenominator maximum denominator value allowed. * @param maxIterations maximum number of convergents * @throws FractionConversionException if the continued fraction failed to * converge. */ private Fraction(double value, double epsilon, int maxDenominator, int maxIterations) throws FractionConversionException { long overflow = Integer.MAX_VALUE; double r0 = value; long a0 = (long)Math.floor(r0); if (a0 > overflow) { throw new FractionConversionException(value, a0, 1l); } // check for (almost) integer arguments, which should not go // to iterations. if (Math.abs(a0 - value) < epsilon) { this.numerator = (int) a0; this.denominator = 1; return; } long p0 = 1; long q0 = 0; long p1 = a0; long q1 = 1; long p2 = 0; long q2 = 1; int n = 0; boolean stop = false; do { ++n; double r1 = 1.0 / (r0 - a0); long a1 = (long)Math.floor(r1); p2 = (a1 * p1) + p0; q2 = (a1 * q1) + q0; if ((p2 > overflow) || (q2 > overflow)) { throw new FractionConversionException(value, p2, q2); } double convergent = (double)p2 / (double)q2; if (n < maxIterations && Math.abs(convergent - value) > epsilon && q2 < maxDenominator) { p0 = p1; p1 = p2; q0 = q1; q1 = q2; a0 = a1; r0 = r1; } else { stop = true; } } while (!stop); if (n >= maxIterations) { throw new FractionConversionException(value, maxIterations); } if (q2 < maxDenominator) { this.numerator = (int) p2; this.denominator = (int) q2; } else { this.numerator = (int) p1; this.denominator = (int) q1; } } /** * Create a fraction given the numerator and denominator. The fraction is * reduced to lowest terms. * @param num the numerator. * @param den the denominator. * @throws ArithmeticException if the denomiator is <code>zero</code> */ public Fraction(int num, int den) { super(); if (den == 0) { throw new ArithmeticException("The denominator must not be zero"); } if (den < 0) { if (num == Integer.MIN_VALUE || den == Integer.MIN_VALUE) { throw new ArithmeticException("overflow: can't negate"); } num = -num; den = -den; } // reduce numerator and denominator by greatest common denominator. int d = MathUtils.gcd(num, den); if (d > 1) { num /= d; den /= d; } // move sign to numerator. if (den < 0) { num *= -1; den *= -1; } this.numerator = num; this.denominator = den; } /** * Returns the absolute value of this fraction. * @return the absolute value. */ public Fraction abs() { Fraction ret; if (numerator >= 0) { ret = this; } else { ret = negate(); } return ret; } /** * Compares this object to another based on size. * @param object the object to compare to * @return -1 if this is less than <tt>object</tt>, +1 if this is greater * than <tt>object</tt>, 0 if they are equal. */ public int compareTo(Object object) { int ret = 0; if (this != object) { Fraction other = (Fraction)object; double first = doubleValue(); double second = other.doubleValue(); if (first < second) { ret = -1; } else if (first > second) { ret = 1; } } return ret; } /** * Gets the fraction as a <tt>double</tt>. This calculates the fraction as * the numerator divided by denominator. * @return the fraction as a <tt>double</tt> */ public double doubleValue() { return (double)numerator / (double)denominator;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -