Java の分数

Rashmi Patidar 2023年10月12日

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

ユーザー定義型の `RationalNumber` を返します。この関数は、最初に、適切な検証とパターンを使用して入力文字列をチェックします。入力文字列は、指数、小数、および全体に分けられます。これらの個々の壊れた値が組み合わさって、有理数を形成します。

• 出力ストリームに有理数を出力します。通常、インスタンスが出力されるたびに、デフォルトの `toString` メソッドが呼び出されます。このメソッドは、クラスの名前に続いて、メモリ位置の 16 進表現を出力します。ただし、ここでは、関数がオーバーライドされて、`p/q` 形式で数値を表す別の実装が提供されます。
• `negate` 関数は、`BigInteger` クラスの `negate` メソッドを呼び出すことにより、内部的に有理数を否定します。有理数の前にマイナス記号を追加します。
• 逆関数は、内部的に `canonical` メソッドを呼び出しますが、違いは 1つだけです。内部的に 3 番目の `checkGcd` パラメータを false として渡します。入力値がブール値 true の場合、メソッドロジックは、分数を最大公約数で除算することにより、有理数を単純化します。しかし、この場合、単純化せずに反転する必要があります。
• `intValue` 関数は、最初にインスタンスが`整数`値であるかどうかをチェックします。`整数`は、正、負、またはゼロの数値ですが、分数にすることはできません。したがって、内部的には、分子と分母に対して `divide` メソッドを呼び出します。このメソッドは `BigInteger` クラスで指定され、`BigInteger` 値を返します。また、分母が`ゼロ`の値を求めると、`ArithmeticException` をスローします。戻り値は、`intValue` 関数を使用して `int` 値に変換されます。
• `longValue` 関数は内部で除算関数を呼び出し、`BigInteger` 出力を `long` データ型に解析します。
• `floatValue` 関数は、有理数の浮動小数点値を提供します。そして、`doubleValue()` 関数のように、`Double` データ型で出力をタイプキャストします。

プロセス全体は、`r1` インスタンスである最初の有理数インスタンスで呼び出されます。同様のシーケンスが再び繰り返され、合理的なインスタンス `r2` に対して出力されます。

Java の分数の数学演算

ここで、加算、減算、除算、乗算、および累乗算術演算には、評価のために 2つのオペランドが必要です。それでは、以下で方法について詳しく説明しましょう。

1. `add` 関数は、分子値が正、負、またはゼロであるかどうかを最初にチェックします。ゼロ以外の場合は、両方の有理数の分母が同じであるかどうかを確認します。同じものが見つかった場合は、分子値を加算し、形成された有理数を返します。それ以外の場合、類似していない場合は、有理数の加算のロジックを定義します。
2. `subtract` メソッドは、渡された 2 番目の有理数インスタンスを否定した後、内部的に `add` メソッドを呼び出します。
3. `multiply` メソッドは、内部的に非常に複雑なロジックを持っています。分子がいずれかの有理数のゼロであるかどうかをチェックし、出力をゼロ値として返します。ゼロでない場合は、分子をいずれかのセットの分母でチェックします。つまり、`r1` 分子は `r2` 分母でチェックされ、その逆も同様です。一致する条件がない場合、`r1` の分子は `r2` インスタンス分子に乗算され、両方の分母が乗算されます。最後に、`BigInteger` クラスの `multiply` 関数を呼び出して乗算を実行します。
4. `divide` 関数は渡されたインスタンスを反転し、最初のインスタンスを使用して `multiply` 関数を内部的に呼び出します。
5. 最後は、`r2` インスタンスの 2 乗を評価する `pow` 関数です。`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.