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
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.
LinkedIn