HOWTO · Java
Java의 분수
이 기사에서는 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이 항상 참이어야하는 표준 또는 표준 형식입니다. 이 방법에는 유리수의 기본 조건을 만족시키기 위해 작성된 논리가 있습니다. 분자와 분모의 부호를 별도로 확인하고 연산을 수행합니다. 분모 값을 확인합니다. 0이면 작업에서except가 발생합니다. 또한 분자 및 분모 값에서최대 공약수또는gcd를 확인합니다. gcd함수는BigInteger값을 리턴하는BigInteger클래스에 있습니다.
계속해서convert메소드가 호출되어 생성되는 첫 번째 유리수 인스턴스를 전달합니다. 이 메서드는 또한 전달되는합리적 숫자인스턴스에 대해 7 개의 서로 다른 함수를 호출합니다.
아래에서 이러한 각 방법을 더 잘 이해할 수 있습니다.
- 인쇄 스트림에 유리수를 인쇄합니다. 일반적으로 인스턴스가 인쇄 될 때마다 기본
toString메소드가 호출됩니다. 이 메서드는 메모리 위치의 16 진수 표현 뒤에 클래스 이름을 인쇄합니다. 그러나 여기서는p/q형식의 숫자를 나타내는 또 다른 구현을 제공하도록 함수가 재정의됩니다. negate함수는BigInteger클래스의negate메소드를 호출하여 내부적으로 유리수를 부정합니다. 유리수 앞에 빼기 기호를 추가합니다.- invert 함수는 내부적으로 하나의 차이점을 가지고
canonical메소드를 호출합니다. 내부적으로 세 번째checkGcd매개 변수를 false로 전달합니다. 입력 값이 부울 참이면 메서드 논리는 분수를 최대 공약수로 나누어 유리수를 단순화합니다. 그러나이 경우 단순화없이 반전해야합니다. intValue함수는 먼저 인스턴스가Integer값인지 확인합니다.정수는 양수, 음수 또는 0 일 수 있지만 분수 일 수는 없습니다. 따라서 내부적으로 분자와 분모에 대해divide메소드를 호출합니다. 이 메서드는BigInteger클래스에 제공되며BigInteger값을 반환합니다. 또한 분모가zero값을 찾으면ArithmeticException이 발생합니다. 반환 된 값은intValue함수를 사용하여int값으로 변환됩니다.longValue함수는 내부적으로 나누기 함수를 호출하고BigInteger출력을long데이터 유형으로 구문 분석합니다.floatValue함수는 유리수의 부동 소수점 값을 제공합니다. 결과를Double데이터 유형으로 형변환하는doubleValue()함수도 마찬가지입니다.
전체 프로세스는r1인스턴스 인 초기 유리수 인스턴스에서 호출됩니다. 유사한 시퀀스가 다시 반복되고 합리적인 인스턴스r2에 대해 인쇄됩니다.
Java의 분수에 대한 수학 연산
이제 더하기, 빼기, 나누기, 곱하기 및 거듭 제곱 산술 연산에는 평가를 위해 두 개의 피연산자가 필요합니다. 따라서 아래에서 방법에 대해 자세히 설명하겠습니다.
add함수는 먼저 분자 값이 양수, 음수 또는 0인지 확인합니다. 0이 아니면 두 유리수의 분모가 같은지 확인합니다. 동일한 값을 찾으면 분자 값을 더하고 형성된 유리수를 반환합니다. 유사하지 않은 경우 유리수 추가 논리를 정의합니다.subtract메소드는 전달 된 두 번째 유리수 인스턴스를 부정한 후 내부적으로add메소드를 호출합니다.multiply방법은 내부적으로 상당히 복잡한 논리를 가지고 있습니다. 분자가 유리수 중 하나의 0인지 확인하고 출력을 0 값으로 반환합니다. 0이 아니면 두 세트의 분모로 분자를 확인합니다. 즉,r1분자는r2분모로 확인되며 그 반대의 경우도 마찬가지입니다. 조건이 일치하지 않으면r1의 분자가r2인스턴스 분자에 곱해지고 두 분모가 모두 곱해집니다. 마지막으로BigInteger클래스의multiply함수를 호출하여 곱셈을 수행합니다.divide함수는 전달 된 인스턴스를 반전하고 내부적으로 첫 번째 인스턴스를 사용하여multiply함수를 호출합니다.- 마지막은
r2인스턴스의 두 번째 거듭 제곱을 평가하는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