Java 中的分数

在数学上,分数是值的部分或部分。当一个物体以一定的比例被均等地分解时,所形成的值称为分数。分数分为有理数和无理数。

在 Java 编程语言中,有一种特权可以对分数执行各种运算,例如数学过程。可以对小数进行加、减、乘、除运算。

下面是演示用户定义类中的有理数操作的代码块。

import java.math.BigInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RationalNumber {
    public final static RationalNumber ZERO = new RationalNumber(BigInteger.ZERO, BigInteger.ONE);
    private final BigInteger numerator, denominator;
    private RationalNumber(BigInteger numerator, BigInteger denominator) {
        this.numerator = numerator;
        this.denominator = denominator;
    }
    private static RationalNumber canonical(BigInteger numerator, BigInteger denominator, boolean checkGcd) {
        if (denominator.signum() == 0) {
            throw new IllegalArgumentException("denominator is zero");
        }
        if (numerator.signum() == 0) {
            return ZERO;
        }
        if (denominator.signum() < 0) {
            numerator = numerator.negate();
            denominator = denominator.negate();
        }
        if (checkGcd) {
            BigInteger gcd = numerator.gcd(denominator);
            if (!gcd.equals(BigInteger.ONE)) {
                numerator = numerator.divide(gcd);
                denominator = denominator.divide(gcd);
            }
        }
        return new RationalNumber(numerator, denominator);
    }
    public static RationalNumber getInstance(long numerator, long denominator) {
        return canonical(new BigInteger("" + numerator), new BigInteger("" + denominator), true);
    }
    public static RationalNumber valueOf(String s) {
        Pattern p = Pattern.compile("(-?\\d+)(?:.(\\d+)?)?0*(?:e(-?\\d+))?");
        Matcher m = p.matcher(s);
        if (!m.matches()) {
            throw new IllegalArgumentException("Unknown format '" + s + "'");
        }
        String whole = m.group(1);
        String decimal = m.group(2);
        String exponent = m.group(3);
        String n = whole;
        if (decimal != null) {
            n += decimal;
        }
        BigInteger numerator = new BigInteger(n);
        int exp = exponent == null ? 0 : Integer.valueOf(exponent);
        int decimalPlaces = decimal == null ? 0 : decimal.length();
        exp -= decimalPlaces;
        BigInteger denominator;
        if (exp < 0) {
            denominator = BigInteger.TEN.pow(-exp);
        } else {
            numerator = numerator.multiply(BigInteger.TEN.pow(exp));
            denominator = BigInteger.ONE;
        }
        return canonical(numerator, denominator, true);
    }
    public static void main(String[] args) {
        RationalNumber r1 = RationalNumber.valueOf("3.14e4");
        RationalNumber r2 = RationalNumber.getInstance(111, 7);
        convert("r1", r1);
        convert("r2", r2);
        convert("r1 + r2", r1.add(r2));
        convert("r1 - r2", r1.subtract(r2));
        convert("r1 * r2", r1.multiply(r2));
        convert("r1 / r2", r1.divide(r2));
        convert("r2 ^ 2", r2.pow(2));
    }
    public static void convert(String name, RationalNumber r) {
        System.out.printf("%s = %s%n", name, r);
        System.out.printf("%s.negate() = %s%n", name, r.negate());
        System.out.printf("%s.invert() = %s%n", name, r.invert());
        System.out.printf("%s.intValue() = %,d%n", name, r.intValue());
        System.out.printf("%s.longValue() = %,d%n", name, r.longValue());
        System.out.printf("%s.floatValue() = %,f%n", name, r.floatValue());
        System.out.printf("%s.doubleValue() = %,f%n", name, r.doubleValue());
        System.out.println();
    }
    public RationalNumber add(RationalNumber o) {
        if (o.numerator.signum() == 0) {
            return this;
        } else if (numerator.signum() == 0) {
            return o;
        } else if (denominator.equals(o.denominator)) {
            return new RationalNumber(numerator.add(o.numerator), denominator);
        } else {
            return canonical(numerator.multiply(o.denominator).add(o.numerator.multiply(denominator)), denominator.multiply(o.denominator), true);
        }
    }
    public RationalNumber multiply(RationalNumber o) {
        if (numerator.signum() == 0 || o.numerator.signum() == 0) {
            return ZERO;
        } else if (numerator.equals(o.denominator)) {
            return canonical(o.numerator, denominator, true);
        } else if (o.numerator.equals(denominator)) {
            return canonical(numerator, o.denominator, true);
        } else if (numerator.negate().equals(o.denominator)) {
            return canonical(o.numerator.negate(), denominator, true);
        } else if (o.numerator.negate().equals(denominator)) {
            return canonical(numerator.negate(), o.denominator, true);
        } else {
            return canonical(numerator.multiply(o.numerator), denominator.multiply(o.denominator), true);
        }
    }
    public boolean isInteger() {
        return numerator.signum() == 0 || denominator.equals(BigInteger.ONE);
    }
    public RationalNumber negate() {
        return new RationalNumber(numerator.negate(), denominator);
    }
    public RationalNumber invert() {
        return canonical(denominator, numerator, false);
    }
    public RationalNumber pow(int exp) {
        return canonical(numerator.pow(exp), denominator.pow(exp), true);
    }
    public RationalNumber subtract(RationalNumber o) {
        return add(o.negate());
    }
    public RationalNumber divide(RationalNumber o) {
        return multiply(o.invert());
    }
    public int intValue() {
        return isInteger() ? numerator.intValue() : numerator.divide(denominator).intValue();
    }
    public long longValue() {
        return isInteger() ? numerator.longValue() : numerator.divide(denominator).longValue();
    }
    public float floatValue() {
        return (float) doubleValue();
    }
    public double doubleValue() {
        return isInteger() ? numerator.doubleValue() : numerator.doubleValue() / denominator.doubleValue();
    }
    @Override
    public String toString() {
        return isInteger() ? String.format("%,d", numerator) : String.format("%,d / %,d", numerator, denominator);
    }
}

在上面的程序中,执行从 main 方法开始。首先,使用类中定义的静态 valueOf() 函数初始化一个有理数。它接受一个字符串值并对输入字符串执行操作。

它返回用户定义类型的 RationalNumber。该函数首先检查具有正确验证和模式的输入字符串。输入字符串被分成指数、小数和整个部分。这些单独的破碎值组合形成一个有理数。

创建有理数的另一种方法是使用 instanceOf() 静态工厂函数。该方法在内部调用 canonical 函数,该函数调用类的私有构造函数。构造函数分离并设置特定实例的分子和分母的值。规范形式,它只是指有理数的标准表示形式。

在给定的情况下,p/q 是标准或规范形式,其中 q!=0 应始终为真。该方法编写了满足有理数基本条件的逻辑。它分别检查分子和分母的符号并执行运算。它检查分母值;如果它是零,操作会抛出一个异常。它还检查分子和分母值中的最大公约数或 gcdgcd 函数存在于返回 BigInteger 值的 BigInteger 类中。

继续前进,调用 convert 方法,传递创建的第一个有理数实例。此方法还在传递的有理数实例上调用七个不同的函数。

下面,你将更好地理解这些方法:

  • 在打印流中打印有理数。通常,每当打印实例时,都会调用默认的 toString 方法。该方法打印类的名称,后跟内存位置的十六进制表示。但在这里,该函数被覆盖以提供另一个表示 p/q 形式的数字的实现。
  • negate 函数将通过调用 BigInteger 类的 negate 方法在内部否定有理数。它将在有理数之前添加一个减号。
  • invert 函数在内部调用 canonical 方法,但只有一个区别。它在内部将第三个 checkGcd 参数作为 false 传递。当输入值为布尔真时,方法逻辑通过将分数除以其最大公约数来简化有理数。但在这种情况下,需要的是不简化的反转。
  • intValue 函数首先检查实例是否为 Integer 值。Integers 是可以是正数、负数或零但不能是分数的数字。因此,它在内部对分子和分母调用 divide 方法。该方法在 BigInteger 类中给出并返回一个 BigInteger 值。当分母为零值时,它也会抛出 ArithmeticException。使用 intValue 函数将返回值转换为 int 值。
  • longValue 函数在内部调用除法函数 snd 将 BigInteger 输出解析为 long 数据类型。
  • floatValue 函数提供有理数的浮点值。doubleValue() 函数也是如此,它以 Double 数据类型对输出进行类型转换。

整个过程调用一个初始有理数实例,即 r1 实例。类似的序列再次重复并为有理实例 r2 打印出来。

Java 中分数的数学运算

现在加、减、除、乘和幂算术运算需要两个操作数进行计算。因此,让我们在下面详细讨论这些方法:

  1. add 函数首先检查分子值是正数、负数还是零。如果非零,则检查两个有理数的分母是否相同。如果发现相同,则将分子值相加并返回形成的有理数。否则,如果没有找到类似的,它定义了有理数加法的逻辑。
  2. subtract 方法在否定传递的第二个有理数实例后在内部调用 add 方法。
  3. multiply 方法内部有相当复杂的逻辑。它检查任一有理数的分子是否为零,并将输出作为零值返回。如果不为零,则使用任一集合的分母检查分子。即 r1 分子与 r2 分母进行检查,反之亦然。当没有条件匹配时,r1 的分子与 r2 实例分子相乘,并且两者的分母相乘。最后,它调用 BigInteger 类的 multiply 函数来执行乘法。
  4. divide 函数将反转传递的实例并使用第一个实例在内部调用 multiply 函数。
  5. 最后是 pow 函数,它计算 r2 实例的二次幂。pow 的实现在 BigInteger 类中定义,该类采用指数进行评估。当指数为负值时,该方法会引发 ArithmeticException 异常。

下面是上面给出的复杂代码的输出:

r1 = 31,400
r1.negate() = -31,400
r1.invert() = 1 / 31,400
r1.intValue() = 31,400
r1.longValue() = 31,400
r1.floatValue() = 31,400.000000
r1.doubleValue() = 31,400.000000
r2 = 111 / 7
r2.negate() = -111 / 7
r2.invert() = 7 / 111
r2.intValue() = 15
r2.longValue() = 15
r2.floatValue() = 15.857142
r2.doubleValue() = 15.857143
r1 + r2 = 219,911 / 7
r1 + r2.negate() = -219,911 / 7
r1 + r2.invert() = 7 / 219,911
r1 + r2.intValue() = 31,415
r1 + r2.longValue() = 31,415
r1 + r2.floatValue() = 31,415.857422
r1 + r2.doubleValue() = 31,415.857143
r1 - r2 = 219,689 / 7
r1 - r2.negate() = -219,689 / 7
r1 - r2.invert() = 7 / 219,689
r1 - r2.intValue() = 31,384
r1 - r2.longValue() = 31,384
r1 - r2.floatValue() = 31,384.142578
r1 - r2.doubleValue() = 31,384.142857
r1 * r2 = 3,485,400 / 7
r1 * r2.negate() = -3,485,400 / 7
r1 * r2.invert() = 7 / 3,485,400
r1 * r2.intValue() = 497,914
r1 * r2.longValue() = 497,914
r1 * r2.floatValue() = 497,914.281250
r1 * r2.doubleValue() = 497,914.285714
r1 / r2 = 219,800 / 111
r1 / r2.negate() = -219,800 / 111
r1 / r2.invert() = 111 / 219,800
r1 / r2.intValue() = 1,980
r1 / r2.longValue() = 1,980
r1 / r2.floatValue() = 1,980.180176
r1 / r2.doubleValue() = 1,980.180180
r2  2 = 12,321 / 49
r2  2.negate() = -12,321 / 49
r2  2.invert() = 49 / 12,321
r2  2.intValue() = 251
r2  2.longValue() = 251
r2  2.floatValue() = 251.448975
r2  2.doubleValue() = 251.448980