# Java 中的分數

Rashmi Patidar 2023年10月12日

``````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.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();
}

if (o.numerator.signum() == 0) {
return this;
} else if (numerator.signum() == 0) {
return o;
} else if (denominator.equals(o.denominator)) {
} else {
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) {
}

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);
}
}
``````

• 在列印流中列印有理數。通常，每當列印例項時，都會呼叫預設的 `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` 資料型別對輸出進行型別轉換。

## 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
``````

Rashmi is a professional Software Developer with hands on over varied tech stack. She has been working on Java, Springboot, Microservices, Typescript, MySQL, Graphql and more. She loves to spread knowledge via her writings. She is keen taking up new things and adopt in her career.