fractions 모듈을 사용하면 rational numbers를 만들고 다룰 수 있어요. 유리수는 정수인 분자를 정수인 분모로 나눈 분수예요.
예를 들어 2/3 같은 값을 근사값인 float 값 0.6666... 대신 정확한 분수로 저장할 수 있어요.
int, float, complex 숫자와 달리 분수에는 리터럴 형태가 없어요.
하지만 분수 생성자는 아주 유연해요.
가장 흔하게는 정수 두 개를 받을 수 있어요. 공약수는 자동으로 약분되어, 분수가 "가장 간단한 형태"(분수를 정확하게 나타내는 가장 작은 정수)로 변환돼요:
>>> from fractions import Fraction
>>> f1 = Fraction(2, 3) # 2/3
>>> f1
Fraction(2, 3)
>>> f2 = Fraction(6, 9)
>>> f2
Fraction(2, 3) # automatically simplified
>>> f1 == f2
True
분수 생성자는 문자열 표현도 파싱할 수 있어요:
>>> f3 = Fraction('2/3')
>>> f3
Fraction(2, 3)
float 매개변수와도 함께 쓸 수 있지만, 소수 값을 내부적으로 이진수로 표현하는 근사 방식 때문에 문제가 생길 수 있어요.
이 표현 문제에 대해 더 알아보려면 0.30000000000000004 웹사이트와 Python 문서의 부동 소수점 산술: 문제점과 한계를 참고해요.
분수와 함께 실수를 사용할 때 더 믿을 만한 결과가 필요하다면 <fraction>.limit_denominator() 메서드를 사용해요.
.limit_denominator()는 특별한 요구 사항이 있으면 정수 매개변수를 받을 수 있지만, 기본값(max_denominator=1000000)만으로도 충분히 잘 동작하고 괜찮은 간단한 근삿값을 줘요.
>>> Fraction(1.2)
Fraction(5404319552844595, 4503599627370496)
>>> Fraction(1.2).limit_denominator()
Fraction(6, 5)
일반적인 arithmetic operators + - * / **는 다른 숫자 타입과 마찬가지로 분수에도 쓸 수 있어요.
정수와 다른 Fraction을 함께 넣어도 결과는 Fraction이에요.
식에 float 타입을 넣으면 결과도 float가 되고, 그에 따라 정밀도가 손실될 수도 있어요.
>>> Fraction(2, 3) + Fraction(1, 4) # addition
Fraction(11, 12)
>>> Fraction(2, 3) * Fraction(6, 5) # multiply fractions
Fraction(4, 5)
>>> Fraction(2, 3) * 6 / 5 # fraction with integers
Fraction(4, 5)
>>> Fraction(2, 3) * 1.2 # fraction with float -> float
0.7999999999999999
>>> Fraction(2, 3) ** 2 # exponentiation with integer
Fraction(4, 9)
분수는 중간 계산에서 정밀도를 유지하는 데 아주 좋지만, 최종 출력에서 원하는 형태가 아닐 수도 있어요.
분자와 분모를 각각 따로 얻거나, 튜플로 얻을 수 있어요 (tuples은 나중에 다룰 개념에서 설명해요):
>>> Fraction(2, 3).numerator
2
>>> Fraction(2, 3).denominator
3
>>> Fraction(2, 3).as_integer_ratio()
(2, 3)
Python의 여러 표준 숫자 함수도 int와 float 타입을 다룰 때 기대하는 결과를 그대로 줘요:
>>> round(Fraction(11, 3))
4
>>> from math import floor, ceil
>>> floor(Fraction(11, 3))
3
>>> ceil(Fraction(11, 3))
4
>>> float(Fraction(11, 3))
3.6666666666666665