【问题标题】:Is there a commonly used rational numbers library in Java?Java中是否有常用的有理数库?
【发布时间】:2011-03-26 13:35:36
【问题描述】:

我正在寻找一个表示分数(有理数)的 Java 库。例如,如果我想存储分数1/3,那么它不会被保存为0.33333,这将失去它的准确性。

以下是我希望在此类库中找到的一些功能:

  • getNumerator()
  • getDenominator()
  • add(Rational r1, Rational r2), subtract(Rational r1, Rational r2), multiply(Rational r1, Rational r2), divide(Rational r1, Rational r2)
  • isProper()
  • getCommonDenominator(Collection<Rational> rationals)
  • getSimplified()

我可以自己实现这样的库,但我想知道是否已经存在类似的东西。

编辑:如果库实现(除上述之外)一些数论算法,例如getEgyptianFractionsSum() 等,那也很好。

【问题讨论】:

    标签: java math


    【解决方案1】:

    Apache Commons Math 适合你吗?

    【讨论】:

      【解决方案2】:

      JScience 库包括类 org.jscience.mathematics.number.Rational。除了通常的工厂、访问器和操作之外,还可以构造其他有用的实体,包括Polynomial<Rational>Vector<Rational>Matrix<Rational>

      例如,获取分数集合的最小公分母的函数可能如下所示:

      private static LargeInteger lcd(Collection<Rational> fractions) {
          Rational sum = Rational.ZERO;
          for (Rational rational : fractions) {
              sum = sum.plus(rational);
          }
          return sum.getDivisor();
      }
      

      以下语句打印6

      System.out.println(lcd(Arrays.asList(
          Rational.valueOf(1, 2), Rational.valueOf(1, 3))));
      

      【讨论】:

      • 严格来说,您的示例通常不会返回最小公分母,而只会返回总和的分母。例如。对于System.out.println(lcd(Arrays.asList(Rational.valueOf(1, 2), Rational.valueOf(1, 2))));,它返回 1,尽管 2 是最小公分母 (1/2 + 1/2 = 2/2 = 1/1)。
      【解决方案3】:

      从未来编辑:请使用 Apache Commons 或任何其他受支持的库。这只是一个示例演示。

      我实现了一个可以用于此目的的小类,也许它对您也有用,请谨慎使用。

      import java.util.ArrayList;
      
      public class RationalNumber {
      
          /**
           *
           * @author Suat KARAKUSOGLU
           * @email  suatkarakusoglu@gmail.com
           * This class has 2 kind of constructors
           * 1. is RationalNumber a=new RationalNumber("3.3");
           *       RationalNumber a=new RationalNumber("-3.3");
           * With this constructor one can enter the decimal number and also specify whether negative or not
           *
           * 2. is RationalNumber a=new RationalNumber(3,5);
           * With this constructor the first value is nominator and second one is denominator.
           *
           * The advantage side of this class is, it prevents the fractional errors while dividing
           * RationalNumber keeps all denominator and nominator values as it is and when the real value is
           * needed, the calculation occurs at that time.
           *
           * Supports multiply,divide,add,subtract operations on RationalNumber classes.
           *
           */
      
      
          /*
           * Simple Usage:
           *
           * RationalNumber a=new RationalNumber("3.3");
           * RationalNumber b=new RationalNumber("4.5");
           * System.out.println("a ="+a.getStringValue());
           * System.out.println("b ="+b.getStringValue());
           * System.out.println("a-b ="+a.subtract(b).getStringValue());
           * System.out.println("a ="+a.getStringValue());
           * System.out.println("b ="+b.getStringValue());
           * RationalNumber k=a.divide(b);
           * System.out.println("a/b="+k.getStringValue());
           * System.out.println("a/b="+k.getDoubleValue());
           *
           * System out results:
           *
           * a =33/10
           * b =9/2
           * a-b =-6/5
           * a =33/10
           * b =9/2
           * a/b=11/15
           * a/b=0.7333333333333333
           *
           */
      
          public ArrayList<Long> nominators = new ArrayList<Long>();
          public ArrayList<Long> denominators = new ArrayList<Long>();
      
          public RationalNumber(String rationalNumberStringValue) {
              this(parseRationalNumberStringValue(rationalNumberStringValue)[0],
                      parseRationalNumberStringValue(rationalNumberStringValue)[1]);
      
          }
      
          private static Long[] parseRationalNumberStringValue(
                  String rationalNumberStringValue) {
      
              boolean positive = true;
              if (rationalNumberStringValue.charAt(0) == '-') {
                  positive = false;
                  rationalNumberStringValue = rationalNumberStringValue.substring(1);
              }
      
              // 0. index is keeping nominator
              // 1. index is keeping denominator
              Long[] nominatorDenominator = new Long[2];
              nominatorDenominator[0] = 1l;
              nominatorDenominator[1] = 1l;
      
              String[] splittedNumberArr = rationalNumberStringValue.split("\\.");
              String denominatorStr = splittedNumberArr[1];
      
              for (int i = 0; i < denominatorStr.length(); i++) {
                  nominatorDenominator[1] *= 10;
              }
      
              rationalNumberStringValue = removeCharAt(rationalNumberStringValue,
                      rationalNumberStringValue.indexOf('.'));
              nominatorDenominator[0] = Long.valueOf(rationalNumberStringValue);
              if (!positive) {
                  nominatorDenominator[0] *= -1;
              }
              return nominatorDenominator;
      
          }
      
          public static String removeCharAt(String s, int pos) {
              return s.substring(0, pos) + s.substring(pos + 1);
          }
      
          public RationalNumber(Integer nominator, Integer denominator) {
      
              this((long) nominator, (long) denominator);
      
          }
      
          public RationalNumber(Long nominator, Long denominator) {
      
              nominators.add(nominator);
              denominators.add(denominator);
              simplify();
      
          }
      
          public RationalNumber(ArrayList<Long> nominatorList,
                  ArrayList<Long> denominatorList) {
      
              nominators.addAll(nominatorList);
              denominators.addAll(denominatorList);
              simplify();
      
          }
      
          public String getStringValue() {
              return getMultipliedValue(this.nominators) + "/"
                      + getMultipliedValue(this.denominators);
          }
      
          public double getDoubleValue() {
              return (double) getMultipliedValue(this.nominators)
                      / (double) getMultipliedValue(this.denominators);
          }
      
          public RationalNumber multiply(RationalNumber rationalNumberToMultiply) {
      
              RationalNumber mulResult = new RationalNumber(
                      rationalNumberToMultiply.nominators,
                      rationalNumberToMultiply.denominators);
              mulResult.nominators.addAll(this.nominators);
              mulResult.denominators.addAll(this.denominators);
      
              return RationalNumber.simplifyRationalNumber(mulResult);
          }
      
          public RationalNumber divide(RationalNumber rationalNumberToDivide) {
      
              RationalNumber divideResult = new RationalNumber(
                      rationalNumberToDivide.nominators,
                      rationalNumberToDivide.denominators);
      
              // division means multiplication with reverse values
              ArrayList<Long> tempLongList = divideResult.nominators;
              divideResult.nominators = divideResult.denominators;
              divideResult.denominators = tempLongList;
      
              return this.multiply(divideResult);
      
          }
      
          public RationalNumber add(RationalNumber rationalNumberToAdd) {
      
              rationalNumberToAdd = RationalNumber
                      .simplifyRationalNumber(rationalNumberToAdd);
      
              return new RationalNumber(
                      (getMultipliedValue(this.nominators) * getMultipliedValue(rationalNumberToAdd.denominators))
                              + (getMultipliedValue(this.denominators) * getMultipliedValue(rationalNumberToAdd.nominators)),
                      (getMultipliedValue(this.denominators) * getMultipliedValue(rationalNumberToAdd.denominators)));
      
          }
      
          public RationalNumber subtract(RationalNumber rationalNumberToSubtract) {
      
              rationalNumberToSubtract = RationalNumber
                      .simplifyRationalNumber(rationalNumberToSubtract);
      
              RationalNumber subtractTempRational = new RationalNumber(
                      rationalNumberToSubtract.nominators,
                      rationalNumberToSubtract.denominators);
      
              // Multiply one of its nominators negative value
              subtractTempRational.nominators.set(0,
                      (subtractTempRational.nominators.get(0) * -1));
      
              // add with its negative value
              return this.add(subtractTempRational);
      
          }
      
          private long getMultipliedValue(ArrayList<Long> longList) {
              Long mulResult = 1l;
              for (Long tempLong : longList) {
                  mulResult *= tempLong;
              }
              return mulResult;
          }
      
          // simplifies original rationalnumber
          public void simplify() {
              long tempGcd = 1;
              long iValue = 1;
              long jValue = 1;
              for (int i = 0; i < this.nominators.size(); i++) {
                  iValue = this.nominators.get(i);
                  for (int j = 0; j < this.denominators.size(); j++) {
                      jValue = this.denominators.get(j);
                      tempGcd = gcd(iValue, jValue);
                      this.nominators.set(i, iValue / tempGcd);
                      this.denominators.set(j, jValue / tempGcd);
                  }
              }
          }
      
          public static RationalNumber simplifyRationalNumber(
                  RationalNumber rationalNumberToSimplify) {
              long tempGcd = 1;
              long iValue = 1;
              long jValue = 1;
              for (int i = 0; i < rationalNumberToSimplify.nominators.size(); i++) {
                  for (int j = 0; j < rationalNumberToSimplify.denominators.size(); j++) {
                      iValue = rationalNumberToSimplify.nominators.get(i);
                      jValue = rationalNumberToSimplify.denominators.get(j);
                      tempGcd = gcd(iValue, jValue);
                      rationalNumberToSimplify.nominators.set(i, iValue / tempGcd);
                      rationalNumberToSimplify.denominators.set(j, jValue / tempGcd);
                  }
              }
              return rationalNumberToSimplify;
          }
      
          // Euclidean algorithm to find greatest common divisor
          public static long gcd(long a, long b) {
      
              a = Math.abs(a);
              b = Math.abs(b);
      
              if (a < b) {
                  long temp = a;
                  a = b;
                  b = temp;
              }
      
              if (b == 0)
                  return a;
              else
                  return gcd(b, a % b);
          }
      
          public RationalNumber add(int integerToAdd) {
      
              RationalNumber tempRationalNumber=new RationalNumber(integerToAdd,1);
              return this.add(tempRationalNumber);
          }
          public RationalNumber subtract(int integerToSubtract) {
      
              RationalNumber tempRationalNumber=new RationalNumber(integerToSubtract,1);
              return this.subtract(tempRationalNumber);
          }
          public RationalNumber multiply(int integerToMultiply) {
      
              RationalNumber tempRationalNumber=new RationalNumber(integerToMultiply,1);
              return this.multiply(tempRationalNumber);
          }
          public RationalNumber divide(int integerToDivide) {
      
              RationalNumber tempRationalNumber=new RationalNumber(integerToDivide,1);
              return this.divide(tempRationalNumber);
          }
      
      
      
      }
      

      【讨论】:

      • 这个几百行长的类怎么算得上“小”? ò.O
      • 我不希望这样的库一定很小,但为了符合图书馆的资格,它应该“正式”发布在某个地方,而不仅仅是在 Stack Overflow 的答案中。
      • 你是绝对正确的 Roland!,我没有声称这是某种库,我也警告过它的用法:),这只是我写的一个试用解决方案展示如何在多年前实现这一目标。我已经编辑了答案,以便人们更加小心使用。
      【解决方案4】:

      我不确定它有多常用,但 apfloat 包(Java 和 C++)包含 a class for rational arithmetic

      【讨论】:

        【解决方案5】:

        Apfloat 库具有许多出色的功能、性能、准确性等。它绝对是一个更好的 BigDecimal,它是公平的,但非常简单并且提供的功能很少。

        http://www.apfloat.org/apfloat_java/

        内容:

        类路径设置 第一个例子 建造漂浮物 Double 和 float 构造函数注意事项 Apfloat 是不可变的 精确 输出 高级数学函数 整数 复数 有理数 使用 10 以外的其他基数 平等与比较 格式化

        【讨论】:

          【解决方案6】:

          您可能想试试RationalJ,这是一个用于有理数的 Java 库。

          【讨论】:

            猜你喜欢
            • 2011-07-25
            • 2011-11-05
            • 2010-11-08
            • 1970-01-01
            • 1970-01-01
            • 2012-07-21
            • 1970-01-01
            • 2016-12-09
            • 1970-01-01
            相关资源
            最近更新 更多