栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

表示Java分数的最佳方法?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

表示Java分数的最佳方法?

碰巧的是不久前我写了一个BigFraction类,用于解决Euler项目问题。它保留了BigInteger分子和分母,因此它将永远不会溢出。但是,对于许多你永远不会溢出的操作来说,这会有点慢。无论如何,请根据需要使用它。我一直很想以某种方式炫耀它。:)

编辑:该代码的最新,最出色的版本,包括单元测试,现在托管在GitHub上,也可以通过Maven Central获得。我将原始代码留在这里,以便此答案不仅仅是一个链接…

import java.math.*;public final class BigFraction extends Number implements Comparable<BigFraction>{  private static final long serialVersionUID = 1L; //because Number is Serializable  private final BigInteger numerator;  private final BigInteger denominator;  public final static BigFraction ZERO = new BigFraction(BigInteger.ZERO, BigInteger.ONE, true);  public final static BigFraction ONE = new BigFraction(BigInteger.ONE, BigInteger.ONE, true);    public BigFraction(BigInteger numerator, BigInteger denominator)  {    if(numerator == null)      throw new IllegalArgumentException("Numerator is null");    if(denominator == null)      throw new IllegalArgumentException("Denominator is null");    if(denominator.equals(BigInteger.ZERO))      throw new ArithmeticException("Divide by zero.");    //only numerator should be negative.    if(denominator.signum() < 0)    {      numerator = numerator.negate();      denominator = denominator.negate();    }    //create a reduced fraction    BigInteger gcd = numerator.gcd(denominator);    this.numerator = numerator.divide(gcd);    this.denominator = denominator.divide(gcd);  }    public BigFraction(BigInteger numerator)  {    this(numerator, BigInteger.ONE, true);  }  public BigFraction(long numerator, long denominator)  {    this(BigInteger.valueOf(numerator), BigInteger.valueOf(denominator));  }  public BigFraction(long numerator)  {    this(BigInteger.valueOf(numerator), BigInteger.ONE, true);  }    public BigFraction(double d)  {    if(Double.isInfinite(d))      throw new IllegalArgumentException("double val is infinite");    if(Double.isNaN(d))      throw new IllegalArgumentException("double val is NaN");    //special case - math below won't work right for 0.0 or -0.0    if(d == 0)    {      numerator = BigInteger.ZERO;      denominator = BigInteger.ONE;      return;    }    final long bits = Double.doubleToLongBits(d);    final int sign = (int)(bits >> 63) & 0x1;    final int exponent = ((int)(bits >> 52) & 0x7ff) - 0x3ff;    final long mantissa = bits & 0xfffffffffffffL;    //number is (-1)^sign * 2^(exponent) * 1.mantissa    BigInteger tmpNumerator = BigInteger.valueOf(sign==0 ? 1 : -1);    BigInteger tmpDenominator = BigInteger.ONE;    //use shortcut: 2^x == 1 << x.  if x is negative, shift the denominator    if(exponent >= 0)      tmpNumerator = tmpNumerator.multiply(BigInteger.ONE.shiftLeft(exponent));    else      tmpDenominator = tmpDenominator.multiply(BigInteger.ONE.shiftLeft(-exponent));    //1.mantissa == 1 + mantissa/2^52 == (2^52 + mantissa)/2^52    tmpDenominator = tmpDenominator.multiply(BigInteger.valueOf(0x10000000000000L));    tmpNumerator = tmpNumerator.multiply(BigInteger.valueOf(0x10000000000000L + mantissa));    BigInteger gcd = tmpNumerator.gcd(tmpDenominator);    numerator = tmpNumerator.divide(gcd);    denominator = tmpDenominator.divide(gcd);  }    public BigFraction(double numerator, double denominator)  {    if(denominator == 0)      throw new ArithmeticException("Divide by zero.");    BigFraction tmp = new BigFraction(numerator).divide(new BigFraction(denominator));    this.numerator = tmp.numerator;    this.denominator = tmp.denominator;  }    public BigFraction(BigDecimal d)  {    this(d.scale() < 0 ? d.unscaledValue().multiply(BigInteger.TEN.pow(-d.scale())) : d.unscaledValue(),         d.scale() < 0 ? BigInteger.ONE : BigInteger.TEN.pow(d.scale()));  }  public BigFraction(BigDecimal numerator, BigDecimal denominator)  {    if(denominator.equals(BigDecimal.ZERO))      throw new ArithmeticException("Divide by zero.");    BigFraction tmp = new BigFraction(numerator).divide(new BigFraction(denominator));    this.numerator = tmp.numerator;    this.denominator = tmp.denominator;  }    public BigFraction(String s)  {    int slashPos = s.indexOf('/');    if(slashPos < 0)    {      BigFraction res = new BigFraction(new BigDecimal(s));      this.numerator = res.numerator;      this.denominator = res.denominator;    }    else    {      BigDecimal num = new BigDecimal(s.substring(0, slashPos));      BigDecimal den = new BigDecimal(s.substring(slashPos+1, s.length()));      BigFraction res = new BigFraction(num, den);      this.numerator = res.numerator;      this.denominator = res.denominator;    }  }    public BigFraction add(BigFraction f)  {    if(f == null)      throw new IllegalArgumentException("Null argument");    //n1/d1 + n2/d2 = (n1*d2 + d1*n2)/(d1*d2)     return new BigFraction(numerator.multiply(f.denominator).add(denominator.multiply(f.numerator)),     denominator.multiply(f.denominator));  }    public BigFraction add(BigInteger b)  {    if(b == null)      throw new IllegalArgumentException("Null argument");    //n1/d1 + n2 = (n1 + d1*n2)/d1    return new BigFraction(numerator.add(denominator.multiply(b)),     denominator, true);  }    public BigFraction add(long n)  {    return add(BigInteger.valueOf(n));  }    public BigFraction subtract(BigFraction f)  {    if(f == null)      throw new IllegalArgumentException("Null argument");    return new BigFraction(numerator.multiply(f.denominator).subtract(denominator.multiply(f.numerator)),     denominator.multiply(f.denominator));  }    public BigFraction subtract(BigInteger b)  {    if(b == null)      throw new IllegalArgumentException("Null argument");    return new BigFraction(numerator.subtract(denominator.multiply(b)),     denominator, true);  }    public BigFraction subtract(long n)  {    return subtract(BigInteger.valueOf(n));  }    public BigFraction multiply(BigFraction f)  {    if(f == null)      throw new IllegalArgumentException("Null argument");    return new BigFraction(numerator.multiply(f.numerator), denominator.multiply(f.denominator));  }    public BigFraction multiply(BigInteger b)  {    if(b == null)      throw new IllegalArgumentException("Null argument");    return new BigFraction(numerator.multiply(b), denominator);  }    public BigFraction multiply(long n)  {    return multiply(BigInteger.valueOf(n));  }    public BigFraction divide(BigFraction f)  {    if(f == null)      throw new IllegalArgumentException("Null argument");    if(f.numerator.equals(BigInteger.ZERO))      throw new ArithmeticException("Divide by zero");    return new BigFraction(numerator.multiply(f.denominator), denominator.multiply(f.numerator));  }    public BigFraction divide(BigInteger b)  {    if(b == null)      throw new IllegalArgumentException("Null argument");    if(b.equals(BigInteger.ZERO))      throw new ArithmeticException("Divide by zero");    return new BigFraction(numerator, denominator.multiply(b));  }    public BigFraction divide(long n)  {    return divide(BigInteger.valueOf(n));  }    public BigFraction pow(int exponent)  {    if(exponent == 0)      return BigFraction.ONE;    else if (exponent == 1)      return this;    else if (exponent < 0)      return new BigFraction(denominator.pow(-exponent), numerator.pow(-exponent), true);    else      return new BigFraction(numerator.pow(exponent), denominator.pow(exponent), true);  }    public BigFraction reciprocal()  {    if(this.numerator.equals(BigInteger.ZERO))      throw new ArithmeticException("Divide by zero");    return new BigFraction(denominator, numerator, true);  }    public BigFraction complement()  {    return new BigFraction(denominator.subtract(numerator), denominator, true);  }    public BigFraction negate()  {    return new BigFraction(numerator.negate(), denominator, true);  }    public int signum()  {    return numerator.signum();  }    public BigFraction abs()  {    return (signum() < 0 ? negate() : this);  }    public String toString()  {    return numerator.toString() + "/" + denominator.toString();  }    public boolean equals(Object o)  {    if(!(o instanceof BigFraction))      return false;    BigFraction f = (BigFraction)o;    return numerator.equals(f.numerator) && denominator.equals(f.denominator);  }    public int hashCode()  {    //using the method generated by Eclipse, but streamlined a bit..    return (31 + numerator.hashCode())*31 + denominator.hashCode();  }    public int compareTo(BigFraction f)  {    if(f == null)      throw new IllegalArgumentException("Null argument");    //easy case: this and f have different signs    if(signum() != f.signum())      return signum() - f.signum();    //next easy case: this and f have the same denominator    if(denominator.equals(f.denominator))      return numerator.compareTo(f.numerator);    //not an easy case, so first make the denominators equal then compare the numerators     return numerator.multiply(f.denominator).compareTo(denominator.multiply(f.numerator));  }    public BigFraction min(BigFraction f)  {    if(f == null)      throw new IllegalArgumentException("Null argument");    return (this.compareTo(f) <= 0 ? this : f);  }    public BigFraction max(BigFraction f)  {    if(f == null)      throw new IllegalArgumentException("Null argument");    return (this.compareTo(f) >= 0 ? this : f);  }    public static BigFraction random()  {    return new BigFraction(Math.random());  }  public final BigInteger getNumerator() { return numerator; }  public final BigInteger getDenominator() { return denominator; }  //implementation of Number class.  may cause overflow.  public byte   bytevalue()   { return (byte) Math.max(Byte.MIN_VALUE,    Math.min(Byte.MAX_VALUE,    longValue())); }  public short  shortValue()  { return (short)Math.max(Short.MIN_VALUE,   Math.min(Short.MAX_VALUE,   longValue())); }  public int    intValue()    { return (int)  Math.max(Integer.MIN_VALUE, Math.min(Integer.MAX_VALUE, longValue())); }  public long   longValue()   { return Math.round(doublevalue()); }  public float  floatValue()  { return (float)doublevalue(); }  public double doublevalue() { return toBigDecimal(18).doublevalue(); }    public BigDecimal toBigDecimal()  {    //Implementation note:  A fraction can be represented exactly in base-10 iff its    //denominator is of the form 2^a * 5^b, where a and b are nonnegative integers.    //(In other words, if there are no prime factors of the denominator except for    //2 and 5, or if the denominator is 1).  So to determine if this denominator is    //of this form, continually divide by 2 to get the number of 2's, and then    //continually divide by 5 to get the number of 5's.  Afterward, if the denominator    //is 1 then there are no other prime factors.    //Note: number of 2's is given by the number of trailing 0 bits in the number    int twos = denominator.getLowestSetBit();    BigInteger tmpDen = denominator.shiftRight(twos); // x / 2^n === x >> n    final BigInteger FIVE = BigInteger.valueOf(5);    int fives = 0;    BigInteger[] divMod = null;    //while(tmpDen % 5 == 0) { fives++; tmpDen /= 5; }    while(BigInteger.ZERO.equals((divMod = tmpDen.divideAndRemainder(FIVE))[1]))    {      fives++;      tmpDen = divMod[0];    }    if(BigInteger.ONE.equals(tmpDen))    {      //This fraction will terminate in base 10, so it can be represented exactly as      //a BigDecimal.  We would now like to make the fraction of the form      //unscaled / 10^scale.  We know that 2^x * 5^x = 10^x, and our denominator is      //in the form 2^twos * 5^fives.  So use max(twos, fives) as the scale, and      //multiply the numerator and deminator by the appropriate number of 2's or 5's      //such that the denominator is of the form 2^scale * 5^scale.  (Of course, we      //only have to actually multiply the numerator, since all we need for the      //BigDecimal constructor is the scale.      BigInteger unscaled = numerator;      int scale = Math.max(twos, fives);      if(twos < fives)        unscaled = unscaled.shiftLeft(fives - twos); //x * 2^n === x << n      else if (fives < twos)        unscaled = unscaled.multiply(FIVE.pow(twos - fives));      return new BigDecimal(unscaled, scale);    }    //else: this number will repeat infinitely in base-10.  So try to figure out    //a good number of significant digits.  Start with the number of digits required    //to represent the numerator and denominator in base-10, which is given by    //bitLength / log[2](10).  (bitLenth is the number of digits in base-2).    final double LG10 = 3.321928094887362; //Precomputed ln(10)/ln(2), a.k.a. log[2](10)    int precision = Math.max(numerator.bitLength(), denominator.bitLength());    precision = (int)Math.ceil(precision / LG10);    //If the precision is less than 18 digits, use 18 digits so that the number    //will be at least as accurate as a cast to a double.  For example, with    //the fraction 1/3, precision will be 1, giving a result of 0.3.  This is    //quite a bit different from what a user would expect.    if(precision < 18)      precision = 18;    return toBigDecimal(precision);  }    public BigDecimal toBigDecimal(int precision)  {    return new BigDecimal(numerator).divide(new BigDecimal(denominator), new MathContext(precision, RoundingMode.HALF_EVEN));  }  //--------------------------------------------------------------------------  //  PRIVATE FUNCTIONS  //--------------------------------------------------------------------------    private BigFraction(BigInteger numerator, BigInteger denominator, boolean throwaway)  {    if(denominator.signum() < 0)    {      this.numerator = numerator.negate();      this.denominator = denominator.negate();    }    else    {      this.numerator = numerator;      this.denominator = denominator;    }  }}


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/430208.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号