Java의 분수

Rashmi Patidar 2023년10월12일
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/qq!=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의 분수에 대한 수학 연산

이제 더하기, 빼기, 나누기, 곱하기 및 거듭 제곱 산술 연산에는 평가를 위해 두 개의 피연산자가 필요합니다. 따라서 아래에서 방법에 대해 자세히 설명하겠습니다.

  1. add함수는 먼저 분자 값이 양수, 음수 또는 0인지 확인합니다. 0이 아니면 두 유리수의 분모가 같은지 확인합니다. 동일한 값을 찾으면 분자 값을 더하고 형성된 유리수를 반환합니다. 유사하지 않은 경우 유리수 추가 논리를 정의합니다.
  2. subtract메소드는 전달 된 두 번째 유리수 인스턴스를 부정한 후 내부적으로add메소드를 호출합니다.
  3. multiply방법은 내부적으로 상당히 복잡한 논리를 가지고 있습니다. 분자가 유리수 중 하나의 0인지 확인하고 출력을 0 값으로 반환합니다. 0이 아니면 두 세트의 분모로 분자를 확인합니다. 즉,r1분자는r2분모로 확인되며 그 반대의 경우도 마찬가지입니다. 조건이 일치하지 않으면r1의 분자가r2인스턴스 분자에 곱해지고 두 분모가 모두 곱해집니다. 마지막으로BigInteger클래스의multiply함수를 호출하여 곱셈을 수행합니다.
  4. divide함수는 전달 된 인스턴스를 반전하고 내부적으로 첫 번째 인스턴스를 사용하여multiply함수를 호출합니다.
  5. 마지막은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 Patidar avatar Rashmi Patidar avatar

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

관련 문장 - Java Math