decimal
--- 십진 고정 소수점 및 부동 소수점 산술¶
소스 코드: Lib/decimal.py
decimal
모듈은 빠르고 정확하게 자리 올림 하는 십진 부동 소수 산술을 지원합니다. float
데이터형보다 다음과 같은 몇 가지 장점을 제공합니다:
Decimal "은 사람을 염두에 두고 설계된 부동 소수점 모델에 기반하고, 필연적으로 최고 원리를 갖습니다 -- 컴퓨터는 사람들이 학교에서 배우는 산술과 같은 방식으로 동작하는 산술을 반드시 제공해야 한다." -- 십진 산술 명세에서 발췌.
Decimal 수는 정확하게 표현할 수 있습니다. 반면에,
1.1
과2.2
와 같은 수는, 이진 부동 소수점으로 정확히 표현할 수 없습니다. 최종 사용자는 일반적으로 이진 부동 소수점에서 그러하듯이1.1 + 2.2
가3.3000000000000003
처럼 표시되는 것을 기대하지 않을 것입니다.정확성은 산술에서도 유지됩니다. 십진 부동 소수점에서,
0.1 + 0.1 + 0.1 - 0.3
는 정확하게 0과 같습니다. 이진 부동 소수점에서, 결과는5.5511151231257827e-017
입니다. 0에 가깝지만, 차이가 신뢰할 수 있는 동등성 검사를 방해하고, 차이는 누적 될 수 있습니다. 이러한 이유로, 강한 동등성 불변 조건을 갖는 회계 응용 프로그램에서는 decimal이 선호됩니다.flowdas
십진 소수를 유지하기 때문에, 진법 변환으로 인한 부정확함이 없다는 뜻이지, 산술의 결과를 항상 정확하게 유지할 수 있다는 뜻이 아닙니다. 가령 나눗셈이 수반되면 무한 소수가 만들어질 수 있는데, Decimal 은 무한 소수를 정확하게 표현하지 못합니다. Decimal 은 항상 유한한 정밀도를 유지하고, 자리 올림을 통해 무한 소수의 근사값을 취합니다.
decimal 모듈은 유효 자릿수의 개념을 포함하고 있으므로
1.30 + 1.20
은2.50
입니다. 후행 0은 유효성을 나타내기 위해 유지됩니다. 이것은 화폐 응용에서는 관례적인 표현입니다. 곱셈의 경우, "교과서" 접근법은 피승수의 모든 숫자를 사용합니다. 예를 들어1.3 * 1.2
는1.56
이고,1.30 * 1.20
은1.5600
입니다.flowdas
예전에는 (요즘은 없어졌을 가능성이 높습니다. 중3에게 물어보니 들어본적이 없다네요) 중등 교과 과정에 "유효 숫자" 라는 개념이 포함되어 있었습니다. 유효 숫자는 숫자의 불확실성에 관한 것인데, 주로 실험적으로 어떤 숫자를 얻을 때 쓸모있는 개념입니다. 가령 눈금자로 길이를 측정할 때 보통 마지막 눈금을 쪼개서 읽을겁니다. 가령
1.25
cm. 그런데 정확히 눈금과 일치할 때는1.20
이라고 읽을 것입니다. 이 때1.2
와1.20
은 다르며 끝의0
은 한 수준 높은 정밀도를 표현합니다. 디지털 저울을 읽을 때도 마찬가지 입니다. 소수점 한자리까지 표시하는 저울과 두자리까지 표시하는 저울은 그 정밀도가 다릅니다.하드웨어 기반 이진 부동 소수점과는 달리, decimal 모듈은 사용자가 변경할 수 있는 정밀도(기본값은 28자리)를 가지며, 주어진 문제에 따라 필요한 만큼 커질 수 있습니다:
>>> from decimal import * >>> getcontext().prec = 6 >>> Decimal(1) / Decimal(7) Decimal('0.142857') >>> getcontext().prec = 28 >>> Decimal(1) / Decimal(7) Decimal('0.1428571428571428571428571429')
이진 및 십진 부동 소수점 모두 출판된 표준에 따라 구현됩니다. 내장 float 형이 기능의 적당한 부분만을 드러내지만, decimal 모듈은 표준의 모든 필수 부분을 노출합니다. 필요한 경우, 프로그래머는 자리 올림(rounding) 및 신호(signal) 처리를 완전히 제어할 수 있습니다. 여기에는 정확하지 않은 연산을 차단하기 위한 예외를 사용하여 정확한 산술을 강제하는 옵션이 포함됩니다.
flowdas
rounding 을 흔히 쓰는 "반올림" 대신 "자리 올림" 이라고 번역합니다. decimal 에서 지원하는 rounding 은 8가지인데, 이중 일부만 "반올림"에 해당하기 때문입니다.
flowdas
signal 은
signal
모듈의 시그널과 구분하기위해 "신호" 라고 번역합니다. 하지만 두 signal 이 아주 관계 없는 것은 아닙니다. 부동 소수점 산술은 하드웨어 구현을 염두에 두고 있는 것이고, 실제로 float 형을 통해 제공되고 있는 이진 부동 소수점은 대부분의 플랫폼에서 하드웨어에 기반합니다. 하드웨어에서 지원되는 경우 이진 부동 소수점 신호가SIGFPE
시그널을 통하는 경우가 있습니다. 예전에는fpectl
이라는 모듈을 통해 제한적으로나마 제어할 수 있는 방법을 제공했지만, 사실상 아무도 쓰지 않기 때문에 파이썬 3.7 에서는 아예 제거되었습니다.decimal 모듈은 "편견 없이, (때로 고정 소수점 산술이라고도 불리는) 정확한 자리 올림 없는 십진 산술과 자리 올림 있는 부동 소수점 산술을 모두" 지원하도록 설계되었습니다. -- 십진 산술 명세에서 발췌.
모듈 설계의 중심 개념은 세 가지입니다: 십진수, 산술을 위한 컨텍스트, 신호(signal).
decimal 수는 불변입니다. 부호(sign), 계수(coefficient digits) 및 지수(exponent)로 구성됩니다. 유효성을 유지하기 위해, 계수는 후행 0을 자르지 않습니다. Decimal은 또한 Infinity
, -Infinity
, NaN
과 같은 특별한 값을 포함합니다. 표준은 또한 -0
을 +0
과 구별합니다.
산술 컨텍스트는 정밀도, 자리 올림 규칙, 지수에 대한 제한, 연산 결과를 나타내는 플래그 및 신호가 예외로 처리될지를 결정하는 트랩 활성화기(trap enabler)를 지정하는 환경입니다. 자리 올림 옵션에는 ROUND_CEILING
, ROUND_DOWN
, ROUND_FLOOR
, ROUND_HALF_DOWN
, ROUND_HALF_EVEN
, ROUND_HALF_UP
, ROUND_UP
및 ROUND_05UP
가 있습니다.
신호는 계산 과정에서 발생하는 예외적인 조건의 그룹입니다. 응용 프로그램의 필요에 따라, 신호가 무시되거나, 정보로 간주하거나, 예외로 처리될 수 있습니다. decimal 모듈의 신호는 Clamped
, InvalidOperation
, DivisionByZero
, Inexact
, Rounded
, Subnormal
, Overflow
, Underflow
, FloatOperation
입니다.
각 신호에는 플래그와 트랩 활성화기가 있습니다. 신호와 만났을 때, 플래그가 1로 설정되고 트랩 활성화기가 1로 설정된 경우, 예외가 발생합니다. 플래그는 상태가 유지되므로(sticky) 계산을 감시하기 전에 재설정할 필요가 있습니다.
더 보기
IBM의 일반 십진 산술 명세, The General Decimal Arithmetic Specification.
빠른 시작 자습서¶
decimal을 사용하는 일반적인 시작은 모듈을 임포트하고, getcontext()
로 현재 컨텍스트를 보고, 필요하다면 정밀도, 자리 올림 또는 활성화된 트랩에 대해 새 값을 설정하는 것입니다:
>>> from decimal import *
>>> getcontext()
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
capitals=1, clamp=0, flags=[], traps=[Overflow, DivisionByZero,
InvalidOperation])
>>> getcontext().prec = 7 # 새 정밀도를 설정합니다
Decimal 인스턴스는 정수, 문자열, 실수(float) 또는 튜플로 만들 수 있습니다. 정수 나 실수로 만들면 해당 정수 또는 실수의 정확한 값 변환이 일어납니다. Decimal 수는 "숫자가 아님(Not a number)"을 나타내는 NaN
, 양과 음의 Infinity
및 -0
과 같은 특수한 값을 포함합니다:
>>> getcontext().prec = 28
>>> Decimal(10)
Decimal('10')
>>> Decimal('3.14')
Decimal('3.14')
>>> Decimal(3.14)
Decimal('3.140000000000000124344978758017532527446746826171875')
>>> Decimal((0, (3, 1, 4), -2))
Decimal('3.14')
>>> Decimal(str(2.0 ** 0.5))
Decimal('1.4142135623730951')
>>> Decimal(2) ** Decimal('0.5')
Decimal('1.414213562373095048801688724')
>>> Decimal('NaN')
Decimal('NaN')
>>> Decimal('-Infinity')
Decimal('-Infinity')
FloatOperation
신호를 트랩 하는 경우, 실수로 생성자나 대소비교에서 Decimal 수와 실수(float)를 혼합하면 예외가 발생합니다:
>>> c = getcontext()
>>> c.traps[FloatOperation] = True
>>> Decimal(3.14)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
>>> Decimal('3.5') < 3.7
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
>>> Decimal('3.5') == 3.5
True
flowdas
예제 코드의 마지막에서 볼 수 있듯이, 동등 비교는 예외를 일으키지 않습니다.
또한 3.5 는 이진 부동 소수점으로 정확히 표현할 수 있는 수이기 때문에 비교 결과가 True
입니다.
flowdas
float 가 조용히 Decimal 로 변환되도록하면, float 값으로 이미 정확하지 않은 값이 들어갔을 가능성이
크기 때문에, Decimal 이 제공하는 정확한 산술이 의미가 없어질 수 있습니다. 이 때문에 정확한 산술이
중요한 응용에서는 FloatOperation
신호를 트랩해서 실수로라도 그런일이 일어나는 것을
막습니다.
버전 3.3에 추가.
새로운 Decimal의 유효 숫자는 입력된 숫자의 개수에 의해서만 결정됩니다. 컨텍스트 정밀도 및 자리 올림은 오직 산술 연산 중에만 작용합니다.
>>> getcontext().prec = 6
>>> Decimal('3.0')
Decimal('3.0')
>>> Decimal('3.1415926535')
Decimal('3.1415926535')
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85987')
>>> getcontext().rounding = ROUND_UP
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85988')
C 버전의 내부 제한을 초과하면, Decimal 을 만들 때 InvalidOperation
를 일으킵니다:
>>> Decimal("1e9999999999999999999")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]
버전 3.3에서 변경.
Decimal은 파이썬의 다른 부분들과 잘 어울립니다. 다음은 십진 부동 소수점으로 부린 작은 묘기입니다:
>>> data = list(map(Decimal, '1.34 1.87 3.45 2.35 1.00 0.03 9.25'.split()))
>>> max(data)
Decimal('9.25')
>>> min(data)
Decimal('0.03')
>>> sorted(data)
[Decimal('0.03'), Decimal('1.00'), Decimal('1.34'), Decimal('1.87'),
Decimal('2.35'), Decimal('3.45'), Decimal('9.25')]
>>> sum(data)
Decimal('19.29')
>>> a,b,c = data[:3]
>>> str(a)
'1.34'
>>> float(a)
1.34
>>> round(a, 1)
Decimal('1.3')
>>> int(a)
1
>>> a * 5
Decimal('6.70')
>>> a * b
Decimal('2.5058')
>>> c % a
Decimal('0.77')
그리고 Decimal에는 몇 가지 수학 함수도 있습니다:
>>> getcontext().prec = 28
>>> Decimal(2).sqrt()
Decimal('1.414213562373095048801688724')
>>> Decimal(1).exp()
Decimal('2.718281828459045235360287471')
>>> Decimal('10').ln()
Decimal('2.302585092994045684017991455')
>>> Decimal('10').log10()
Decimal('1')
quantize()
메서드는 숫자를 고정된 지수로 자리 올림 합니다. 이 방법은 종종 결과를 고정된 자릿수로 자리 올림 하는 화폐 응용에 유용합니다.:
>>> Decimal('7.325').quantize(Decimal('.01'), rounding=ROUND_DOWN)
Decimal('7.32')
>>> Decimal('7.325').quantize(Decimal('1.'), rounding=ROUND_UP)
Decimal('8')
flowdas
여기서 "고정된 지수로 자리 올림" 한다는 뜻은, 계수부를 정수로 만들때의 지수부가 지정한 값이 되도록
만든다는 뜻입니다. 때문에 소수점 밑의 자리수를 맞추는 결과를 줍니다.
첫번째 예에서, Decimal('.01')
은 Decimal(1e-2)
와 같아서 지수가 -2
입니다. 따라서
Decimal('732e-2')
가 되도록 자리 올림합니다. (실제로는 ROUND_DOWN
이라서 내림합니다.)
두번째 예에서, Decimal('1.')
는 Decimal('1e0')
이고, 지수가 0
이므로
Decimal('8e0')
으로 올림(ROUND_UP)합니다.
위에서 보듯이, getcontext()
함수는 현재 컨텍스트에 액세스하고 설정을 변경할 수 있게 합니다. 이 방법은 대부분 응용 프로그램의 요구를 충족시킵니다.
고급 작업을 위해, Context() 생성자를 사용하여 대체 컨텍스트를 만드는 것이 유용할 수 있습니다. 대체 컨텍스트를 활성화하려면, setcontext()
함수를 사용하십시오.
표준에 따라, decimal
모듈은 당장 사용할 수 있는 두 개의 표준 컨텍스트 BasicContext
와 ExtendedContext
를 제공합니다. 특히 전자는 많은 트랩이 활성화되어있어 디버깅에 유용합니다:
>>> myothercontext = Context(prec=60, rounding=ROUND_HALF_DOWN)
>>> setcontext(myothercontext)
>>> Decimal(1) / Decimal(7)
Decimal('0.142857142857142857142857142857142857142857142857142857142857')
>>> ExtendedContext
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
capitals=1, clamp=0, flags=[], traps=[])
>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(7)
Decimal('0.142857143')
>>> Decimal(42) / Decimal(0)
Decimal('Infinity')
>>> setcontext(BasicContext)
>>> Decimal(42) / Decimal(0)
Traceback (most recent call last):
File "<pyshell#143>", line 1, in -toplevel-
Decimal(42) / Decimal(0)
DivisionByZero: x / 0
컨텍스트에는 계산 중에 발생하는 예외 조건을 감시하기 위한 신호 플래그도 있습니다. 플래그는 명시적으로 지워질 때까지 설정된 상태로 유지되므로, clear_flags()
메서드를 사용하여 모니터링되는 각 계산 집합 앞에서 플래그를 지우는 것이 가장 좋습니다.
>>> setcontext(ExtendedContext)
>>> getcontext().clear_flags()
>>> Decimal(355) / Decimal(113)
Decimal('3.14159292')
>>> getcontext()
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[])
flags 엔트리는 Pi
에 대한 유리수 근삿값이 자리 올림 되었고 (컨텍스트 정밀도 이상의 숫자가 버려졌습니다) 결과가 부정확하다는 (폐기된 숫자 일부는 0이 아닙니다) 것을 보여줍니다.
flowdas
355/113 은 Pi
와 소수점 6자리까지 일치하는 간단한 유리수 근사값입니다.
개별 트랩은 컨텍스트의 traps
필드에 있는 딕셔너리를 사용해서 설정합니다.:
>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(0)
Decimal('Infinity')
>>> getcontext().traps[DivisionByZero] = 1
>>> Decimal(1) / Decimal(0)
Traceback (most recent call last):
File "<pyshell#112>", line 1, in -toplevel-
Decimal(1) / Decimal(0)
DivisionByZero: x / 0
대부분 프로그램은 프로그램 시작 시에 한 번만 현재 컨텍스트를 조정합니다. 그리고, 많은 응용 프로그램에서, 데이터는 루프 내에서 단일형변환으로 Decimal
로 변환되어, 프로그램 대부분은 다른 파이썬 숫자 형과 별로 다르지 않게 데이터를 조작합니다.
flowdas
대체로 파이썬의 다른 숫자 형과 비슷하게 동작하지만, 정수 나눗셈에 음수가 포함될 때는 차이가 있기 때문에 조심해야합니다. 이 차이에 대해서는 밑에서 설명합니다.
Decimal 객체¶
-
class
decimal.
Decimal
(value="0", context=None)¶ value 를 기반으로 새
Decimal
객체를 만듭니다.value 는 정수, 문자열, 튜플,
float
또는 다른Decimal
객체일 수 있습니다. value 가 주어지지 않으면,Decimal('0')
을 반환합니다. value 가 문자열이면, 앞뒤의 공백 문자 및 밑줄이 제거된 후 십진수 문자열 문법에 맞아야 합니다:sign ::= '+' | '-' digit ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' indicator ::= 'e' | 'E' digits ::= digit [digit]... decimal-part ::= digits '.' [digits] | ['.'] digits exponent-part ::= indicator [sign] digits infinity ::= 'Infinity' | 'Inf' nan ::= 'NaN' [digits] | 'sNaN' [digits] numeric-value ::= decimal-part [exponent-part] | infinity numeric-string ::= [sign] numeric-value | [sign] nan
위의
digit
가 나타나는 곳에는 다른 유니코드 십진수도 허용됩니다. 여기에는 다양한 다른 알파벳(예를 들어, 인도-아라비아와 데바나가리 숫자)의 십진수와 전각 숫자'\uff10'
에서'\uff19'
까지 포함됩니다.flowdas
인도-아라비아 숫자는 우리가 흔히 아라비아 숫자라고 부르는 것이고, 데바나가리(Devanāgarī) 숫자는 고대 인도의 문자입니다.
value 가
tuple
이면, 세 개의 항목으로 구성되어야 합니다, 부호 (0
은 양수,1
은 음수), 숫자의tuple
, 정수 지수. 예를 들어,Decimal((0, (1, 4, 1, 4), -3))
은Decimal('1.414')
를 반환합니다.value 가
float
면, 이진 부동 소수점 값은 손실 없이 정확한 십진수로 변환됩니다. 이 변환에는 종종 53자리 이상의 정밀도가 필요할 수 있습니다. 예를 들어,Decimal(float('1.1'))
은Decimal('1.100000000000000088817841970012523233890533447265625')
로 변환됩니다.context 정밀도는 저장되는 자릿수에 영향을 주지 않습니다. 저장되는 자릿수는 value 의 자릿수만으로 결정됩니다. 예를 들어
Decimal('3.00000')
은 컨텍스트 정밀도가 단지 3이라도 5개의 모든 0을 기록합니다.context 인자의 목적은 value 가 잘못된 문자열인 경우 어떻게 해야할지를 결정하는 것입니다. 컨텍스트가
InvalidOperation
을 트랩하면, 예외가 발생합니다; 그렇지 않으면, 생성자는NaN
의 값을 갖는 새 Decimal을 반환합니다.일단 만들어지면,
Decimal
객체는 불변입니다.버전 3.2에서 변경: 생성자에 대한 인자는 이제
float
인스턴스가 될 수 있습니다.버전 3.3에서 변경:
float
인자는FloatOperation
트랩이 설정되면 예외를 발생시킵니다. 기본적으로 트랩은 꺼져 있습니다.버전 3.6에서 변경: 코드에서의 정수와 부동 소수점 리터럴과 마찬가지로, 밑줄로 무리 지을 수 있습니다.
십진 부동 소수점 객체는
float
나int
와 같은 다른 내장 숫자 형과 많은 성질을 공유합니다. 일반적인 수학 연산과 특수 메서드가 모두 적용됩니다. 마찬가지로, 십진 객체는 복사, 피클, 인쇄, 딕셔너리 키로 사용, 집합 원소로 사용, 비교, 정렬 및 다른 형(가령float
또는int
)으로 코어션될 수 있습니다.Decimal 객체에 대한 산술과 정수 및 실수에 대한 산술에는 약간의 차이가 있습니다. Decimal 객체에 나머지 연산자
%
가 적용될 때, 결과의 부호는 제수의 부호가 아닌 피제수의 부호가 됩니다:>>> (-7) % 4 1 >>> Decimal(-7) % Decimal(4) Decimal('-3')
정수 나눗셈 연산자
//
의 동작 역시 비슷한 차이를 보입니다. 즉, 가장 가까운 정수로 내림하는 대신 실제 몫의 정수 부(0을 향해 자르기)를 돌려줍니다. 그래서 일반적인 항등식x == (x // y) * y + x % y
를 유지합니다:>>> -7 // 4 -2 >>> Decimal(-7) // Decimal(4) Decimal('-1')
%
와//
연산자는 명세에 설명된 대로 각각remainder
와divide-integer
연산을 구현합니다.Decimal 객체는 일반적으로 산술 연산에서 float 나
fractions.Fraction
인스턴스와 결합 할 수 없습니다: 예를 들어,float
에 aDecimal
을 더하려고 하면TypeError
를 일으킵니다. 그러나, 파이썬의 비교 연산자를 사용하여Decimal
인스턴스x
와 다른 숫자y
를 비교할 수 있습니다. 이렇게 해서 서로 다른 형의 숫자 간에 동등 비교를 할 때 혼란스러운 결과를 피합니다.버전 3.2에서 변경:
Decimal
인스턴스와 다른 숫자 형 사이의 혼합형 비교가 이제 완전히 지원됩니다.표준 숫자 속성에 더해, 십진 부동 소수점 객체에는 여러 가지 특별한 메서드가 있습니다:
-
adjusted
()¶ 최상위 숫자만 남을 때까지 계수의 가장 오른쪽 숫자들을 밀어내도록 조정된 지수를 반환합니다.
Decimal('321e+5').adjusted()
는 7을 반환합니다. 소수점으로부터의 최상위 유효 숫자의 위치를 결정하는 데 사용됩니다.flowdas
'321e+5' 를 '3.21e+7' 로 변환한 후에 7 을 취한다는 뜻입니다.
-
as_integer_ratio
()¶ 주어진
Decimal
인스턴스를, 분모가 양수인 기약 분수로 나타내는 정수의 쌍(n, d)
을 돌려줍니다:>>> Decimal('-3.14').as_integer_ratio() (-157, 50)
변환은 정확합니다. 무한대는 OverflowError를, NaN 은 ValueError를 일으킵니다.
flowdas
이 변환이 정확하기는 하지만, 기약 분수를 만들기 때문에 유효 숫자를 모두 보존하지는 않습니다.
>>> Decimal('-3.140').as_integer_ratio() (-157, 50)
버전 3.6에 추가.
-
compare
(other, context=None)¶ 두 Decimal 인스턴스의 값을 비교합니다.
compare()
는 Decimal 인스턴스를 반환하고, 피연산자 중 하나가 NaN이면 결과는 NaN입니다:a 나 b 가 NaN ==> Decimal('NaN') a < b ==> Decimal('-1') a == b ==> Decimal('0') a > b ==> Decimal('1')
flowdas
a.compare(b)
의 결과가 어떻게 되는지에 대한 예시입니다.
-
compare_signal
(other, context=None)¶ 이 연산은, 모든 NaN 이 신호를 준다는 것을 제외하면
compare()
메서드와 같습니다. 즉, 피연산자가 모두 신호를 주는 NaN이 아니면, 모든 조용한 NaN 피연산자가 마치 신호를 주는 NaN 인 것처럼 처리됩니다.
-
compare_total
(other, context=None)¶ 두 개의 피연산자를 숫자 값 대신 추상 표현을 사용하여 비교합니다.
compare()
메서드와 비슷하지만, 결과는Decimal
인스턴스에 대해 전 순서(total ordering)를 부여합니다. 같은 숫자 값을 갖지만 다른 표현의 두Decimal
인스턴스는 이 순서에 의해 다른 것으로 비교됩니다:>>> Decimal('12.0').compare_total(Decimal('12')) Decimal('-1')
조용한 NaN과 신호를 주는 NaN도 전 순서에 포함됩니다. 이 함수의 결과는, 두 피연산자가 같은 표현을 가질 때
Decimal('0')
, 첫 번째 피연산자가 전 순서에서 두 번째 피연산자보다 낮으면Decimal('-1')
, 첫 번째 피연산자가 전 순서에서 두 번째 피연산자보다 높으면Decimal('1')
입니다. 전 순서에 대한 세부 사항은 명세를 참조하십시오.flowdas
전 순서에는 유효 숫자와 특수한 값에 대한 정의가 포함되지만, 일반적인 숫자 값의 대소 관계는 그대로 보존됩니다. 대략 이런 순서를 갖도록 정의됩니다.
-NaN -sNaN -Infinity -127 -1.00 -1 -0.000 -0 0 1.2300 1.23 1E+9 Infinity sNaN NaN
이 연산은 컨텍스트의 영향을 받지 않고, 조용합니다: 어떤 플래그도 변경되지 않고, 어떤 자리 올림도 수행되지 않습니다. 예외적으로, 두 번째 피연산자를 정확하게 변환할 수 없으면 C 버전은 InvalidOperation을 발생시킬 수 있습니다.
-
compare_total_mag
(other, context=None)¶ compare_total()
처럼 두 개의 피연산자를 숫자 값 대신 추상 표현을 사용하여 비교하지만, 각 피연산자의 부호를 무시합니다.x.compare_total_mag(y)
는x.copy_abs().compare_total(y.copy_abs())
와 동등합니다.이 연산은 컨텍스트의 영향을 받지 않고, 조용합니다: 어떤 플래그도 변경되지 않고, 어떤 자리 올림도 수행되지 않습니다. 예외적으로, 두 번째 피연산자를 정확하게 변환할 수 없으면 C 버전은 InvalidOperation을 발생시킬 수 있습니다.
-
conjugate
()¶ 그냥 self를 돌려줍니다. 이 메서드는 Decimal 명세를 준수하기 위한 것뿐입니다.
-
copy_abs
()¶ 인자의 절댓값을 반환합니다. 이 연산은 컨텍스트의 영향을 받지 않고, 조용합니다: 어떤 플래그도 변경되지 않고, 어떤 자리 올림도 수행되지 않습니다.
-
copy_negate
()¶ 인자의 음의 부정을 돌려줍니다. 이 연산은 컨텍스트의 영향을 받지 않고, 조용합니다: 어떤 플래그도 변경되지 않고, 어떤 자리 올림도 수행되지 않습니다.
-
copy_sign
(other, context=None)¶ 두 번째 피연산자의 부호와 같은 부호로 설정된 첫 번째 피연산자의 복사본을 반환합니다. 예를 들어:
>>> Decimal('2.3').copy_sign(Decimal('-1.5')) Decimal('-2.3')
flowdas
이 섹션에서는 인자나 피연산자를 언급할 때는, 서명에 나타나지는 않더라도 항상 self 를 포함해서 말하고 있습니다.
이 연산은 컨텍스트의 영향을 받지 않고, 조용합니다: 어떤 플래그도 변경되지 않고, 어떤 자리 올림도 수행되지 않습니다. 예외적으로, 두 번째 피연산자를 정확하게 변환할 수 없으면 C 버전은 InvalidOperation을 발생시킬 수 있습니다.
-
exp
(context=None)¶ 주어진 숫자에 대한 (자연) 지수 함수
e**x
의 값을 반환합니다. 결과는ROUND_HALF_EVEN
자리 올림 모드를 사용하여 올바르게 자리 올림 됩니다.>>> Decimal(1).exp() Decimal('2.718281828459045235360287471') >>> Decimal(321).exp() Decimal('2.561702493119680037517373933E+139')
-
from_float
(f)¶ float를 십진수로 정확하게 변환하는 클래스 메서드.
Decimal.from_float(0.1) 은 Decimal('0.1')과 같지 않음에 유의하십시오. 0.1은 이진 부동 소수점에서 정확하게 표현할 수 없으므로, 값은 가장 가까운 표현 가능 값인 0x1.999999999999ap-4로 저장됩니다. 십진수로 표시된 해당 값은 0.1000000000000000055511151231257827021181583404541015625 입니다.
>>> Decimal.from_float(0.1) Decimal('0.1000000000000000055511151231257827021181583404541015625') >>> Decimal.from_float(float('nan')) Decimal('NaN') >>> Decimal.from_float(float('inf')) Decimal('Infinity') >>> Decimal.from_float(float('-inf')) Decimal('-Infinity')
버전 3.1에 추가.
-
fma
(other, third, context=None)¶ 합성된 곱셈-덧셈(fused multiply-add). 중간값 self*other의 자리 올림 없이 self*other+third를 반환합니다.
>>> Decimal(2).fma(3, 5) Decimal('11')
-
is_canonical
()¶ 인자가 규범적이면
True
를 반환하고, 그렇지 않으면False
를 반환합니다. 현재Decimal
인스턴스는 항상 규범적이므로 이 연산은 항상True
를 반환합니다.
-
is_normal
(context=None)¶ 인자가 정상(normal) 유한 수이면
True
를 반환합니다. 인자가 0, 비정상(subnormal), 무한대 또는 NaN 이면False
를 반환합니다.flowdas
0 이 아닌 유한 수 중에서 규범적인 형태의 지수가 Emin 이상인 것들을 정상수(normal number)라고 부르고, Emin 보다 작은 것들을 비정상수(subnormal number)라고 부릅니다. 비정상수는 유효숫자를 일부 희생하면서 여전히 계산 가능합니다. 이런 방식으로 다룰 수 있는 최소 지수는
Context.Etiny()
입니다. Emin 근처에서 갑작스럽게 계산을 포기하기 보다, 정확도를 조금씩 잃어가는 것을 허용하고자 하는 것입니다. 이런 방식을 점진적인 언더플로우라고 합니다.
-
ln
(context=None)¶ 피연산자의 자연로그(밑 e)를 반환합니다. 결과는
ROUND_HALF_EVEN
자리 올림 모드를 사용하여 올바르게 반올림됩니다.
-
log10
(context=None)¶ 피연산자의 상용로그를 반환합니다. 결과는
ROUND_HALF_EVEN
자리 올림 모드를 사용하여 올바르게 반올림됩니다.
-
logb
(context=None)¶ 0이 아닌 수의 경우, 피연산자의 조정된 지수를
Decimal
인스턴스로 반환합니다. 피연산자가 0이면Decimal('-Infinity')
가 반환되고DivisionByZero
플래그가 발생합니다. 피연산자가 무한대면Decimal('Infinity')
가 반환됩니다.flowdas
피연산자의 부호를 무시하고 지수부를 취하는 연산입니다.
-
logical_and
(other, context=None)¶ logical_and()
는 두 개의 논리적 피연산자(논리적 피연산자를 보세요)를 취하는 논리적 연산입니다. 결과는 두 피연산자의 자릿수별and
입니다.
-
logical_invert
(context=None)¶ logical_invert()
는 논리적 연산입니다. 결과는 피연산자의 자릿수별 반전입니다.
-
logical_or
(other, context=None)¶ logical_or()
는 두 개의 논리적 피연산자(논리적 피연산자를 보세요)를 취하는 논리적 연산입니다. 결과는 두 피연산자의 자릿수별or
입니다.
-
logical_xor
(other, context=None)¶ logical_xor()
은 두 개의 논리적 피연산자(논리적 피연산자를 보세요)를 취하는 논리적 연산입니다. 결과는 두 피연산자의 자릿수별 배타적 or입니다.
-
max
(other, context=None)¶ 컨텍스트 자리 올림 규칙이 반환되기 전에 적용되고
NaN
값이 (컨텍스트와 신호를 주는지 조용한지에 따라) 신호를 주거나 무시되는 것을 제외하고max(self, other)
와 같습니다.
-
min
(other, context=None)¶ 컨텍스트 자리 올림 규칙이 반환되기 전에 적용되고
NaN
값이 (컨텍스트와 신호를 주는지 조용한지에 따라) 신호를 주거나 무시되는 것을 제외하고min(self, other)
와 같습니다.
-
next_minus
(context=None)¶ 주어진 피연산자보다 작고, 주어진 컨텍스트(또는 context가 주어지지 않으면 현재 스레드의 컨텍스트)에서 표현 가능한 가장 큰 수를 돌려줍니다.
-
next_plus
(context=None)¶ 주어진 피연산자보다 크고, 주어진 컨텍스트(또는 context가 주어지지 않으면 현재 스레드의 컨텍스트)에서 표현 가능한 가장 작은 수를 돌려줍니다.
-
next_toward
(other, context=None)¶ 두 피연산자가 같지 않으면, 두 번째 피연산자의 방향으로 첫 번째 피연산자에 가장 가까운 숫자를 반환합니다. 두 피연산자가 수치로 같으면, 첫 번째 피연산자의 복사본을 반환하는데, 부호를 두 번째 피연산자의 것으로 설정합니다.
-
normalize
(context=None)¶ 가장 오른쪽 끝에 오는 0을 제거하고 결과를
Decimal('0')
과 같은 모든 결과를Decimal('0e0')
으로 변환하여 숫자를 정규화합니다. 등가 클래스의 어트리뷰트에 대한 규범적인 값을 만드는 데 사용됩니다. 예를 들어,Decimal('32.100')
과Decimal('0.321000e+2')
는 모두 같은 값인Decimal('32.1')
로 정규화됩니다.flowdas
이 연산은 정규화라기 보다는, 숫자를 동등 비교가 유지되는 범위내에서 가장 단순한 형태로 환원시키는 것입니다. 실제로 Decimal 명세에서는 이 연산의 이름이
reduce
로 변경되었습니다. 하지만 이 변경의 더 큰 이유는, 이 연산이 정상수(normal number)와 아무 관련이 없다는 것입니다.
-
number_class
(context=None)¶ 피연산자의 클래스 를 설명하는 문자열을 반환합니다. 반환 값은 다음 10개의 문자열 중 하나입니다.
"-Infinity"
, 피연산자가 음의 무한대임을 나타냅니다."-Normal"
, 피연산자가 음의 정상 수임을 나타냅니다."-Subnormal"
, 피연산자가 음의 비정상 수임을 나타냅니다."-Zero"
, 피연산자가 음의 0임을 나타냅니다."+Zero"
, 피연산자가 양의 0임을 나타냅니다."+Subnormal"
, 피연산자가 양의 비정상 수임을 나타냅니다."+Normal"
, 피연산자가 양의 정상 수임을 나타냅니다."+Infinity"
, 피연산자가 양의 무한대임을 나타냅니다."NaN"
, 피연산자가 조용한 NaN(Not a Number)임을 나타냅니다."sNaN"
, 피연산자가 신호를 주는 NaN임을 나타냅니다.
-
quantize
(exp, rounding=None, context=None)¶ 자리 올림 후에 첫 번째 피연산자와 같고 두 번째 피연산자의 지수를 갖는 값을 반환합니다.
>>> Decimal('1.41421356').quantize(Decimal('1.000')) Decimal('1.414')
flowdas
이 연산은 계수부를 정수로 만들때의 지수부가 exp 의 지수부와 같도록 만듭니다. 이 결과 소수점 밑의 자릿수를 exp 와 일치하도록 자리 올림하게됩니다. 때문에 exp 를 자릿수를 표현하는 탬플릿 처럼 사용하면 됩니다.
다른 연산과 달리, quantize 연산 후의 계수의 길이가 정밀도보다 크면,
InvalidOperation
신호를 줍니다. 이는, 에러 조건이 없으면, quantize 된 지수가 항상 오른쪽 피연산자의 지수와 같음을 보장합니다.또한, 다른 연산과는 달리, 결과가 비정상(subnormal)이고 부정확한 경우조차도, quantize는 결코 Underflow 신호를 보내지 않습니다.
두 번째 피연산자의 지수가 첫 번째 피연산자의 지수보다 크면 자리 올림이 필요할 수 있습니다. 이 경우, 자리 올림 모드는 (주어지면)
rounding
인자에 의해 결정됩니다. 그렇지 않으면 주어진context
인자에 의해 결정됩니다; 두 인자 모두 주어지지 않으면, 현재 스레드의 컨텍스트의 자리 올림 모드가 사용됩니다.결과 지수가
Emax
보다 크거나Etiny
보다 작을 때마다 에러가 반환됩니다.
-
remainder_near
(other, context=None)¶ self 를 other 로 나눈 나머지를 반환합니다. 이것은 나머지의 절댓값을 최소화하기 위해 나머지의 부호가 선택된다는 점에서
self % other
와 다릅니다. 좀 더 정확히 말하면, 반환 값은self - n * other
인데, 여기서n
은self / other
의 정확한 값에 가장 가까운 정수이고, 두 개의 정수와의 거리가 같으면 짝수가 선택됩니다.결과가 0이면 그 부호는 self 의 부호가 됩니다.
>>> Decimal(18).remainder_near(Decimal(10)) Decimal('-2') >>> Decimal(25).remainder_near(Decimal(10)) Decimal('5') >>> Decimal(35).remainder_near(Decimal(10)) Decimal('-5')
-
rotate
(other, context=None)¶ 첫 번째 피연산자의 계수를 두 번째 피연산자로 지정된 양만큼 회전한 결과를 반환합니다. 두 번째 피연산자는 -precision에서 precision 범위의 정수여야 합니다. 두 번째 피연산자의 절댓값은 회전할 자리의 수를 나타냅니다. 두 번째 피연산자가 양수면 왼쪽으로 회전합니다; 그렇지 않으면 오른쪽으로 회전합니다. 필요하면 정밀도에 맞추기 위해 첫 번째 피연산자의 계수에 0이 왼쪽에 채워집니다. 첫 번째 피연산자의 부호와 지수는 변경되지 않습니다.
-
same_quantum
(other, context=None)¶ self와 other가 같은 지수를 가졌는지 또는 둘 다
NaN
인지 검사합니다.이 연산은 컨텍스트의 영향을 받지 않고, 조용합니다: 어떤 플래그도 변경되지 않고, 어떤 자리 올림도 수행되지 않습니다. 예외적으로, 두 번째 피연산자를 정확하게 변환할 수 없으면 C 버전은 InvalidOperation을 발생시킬 수 있습니다.
-
scaleb
(other, context=None)¶ 첫 번째 피연산자의 지수를 두 번째 피연산자만큼 조정한 값을 반환합니다. 달리 표현하면, 첫 번째 피연산자에
10**other
를 곱한 값을 반환합니다. 두 번째 피연산자는 정수여야 합니다.
-
shift
(other, context=None)¶ 첫 번째 피연산자의 계수를 두 번째 피연산자로 지정된 양만큼 이동한 결과를 반환합니다. 두 번째 피연산자는 -precision에서 precision 범위의 정수여야 합니다. 두 번째 피연산자의 절댓값은 이동할 자리의 수를 나타냅니다. 두 번째 피연산자가 양수면 왼쪽으로 이동합니다; 그렇지 않으면 오른쪽으로 이동합니다. 이동으로 인해 계수에 들어오는 숫자는 0입니다. 첫 번째 피연산자의 부호와 지수는 변경되지 않습니다.
-
sqrt
(context=None)¶ 인자의 제곱근을 완전한 정밀도로 반환합니다.
-
to_eng_string
(context=None)¶ 문자열로 변환합니다. 지수가 필요하면 공학 표기법을 사용합니다.
공학 표기법의 지수는 3의 배수입니다. 이렇게 하면 소수점 왼쪽에 최대 3자리를 남기게 되고, 하나나 두 개의 후행 0을 추가해야 할 수 있습니다.
예를 들어, 이 메서드는
Decimal('123E+1')
을Decimal('1.23E+3')
으로 변환합니다.flowdas
문자열로 변환하기 때문에,
Decimal('1.23E+3')
이 아니라'1.23E+3'
을 반환합니다.
-
to_integral
(rounding=None, context=None)¶ to_integral_value()
메서드와 같습니다.to_integral
이름은 이전 버전과의 호환성을 위해 유지되었습니다.
-
논리적 피연산자¶
logical_and()
, logical_invert()
, logical_or()
와 logical_xor()
메서드는 인자가 논리적 피연산자 이길 기대합니다. 논리적 피연산자 는 지수와 부호가 모두 0이고 숫자는 모두 0
또는 1
인 Decimal
인스턴스입니다.
flowdas
Decimal('11010')
은 논리적 피연산자이지만, Decimal('-11010')
는
부호가 있기 때문에, Decimal('12')
는 0
과 1
이외의
숫자가 들어있기 때문에 논리적 피연산자가 아닙니다. 논리적 연산은 각 자릿수별로 이루어집니다.
즉, Decimal('101').logical_or(Decimal('10'))
은 Decimal('111')
이 됩니다.
Context 객체¶
컨텍스트는 산술 연산을 위한 환경입니다. 정밀도를 제어하고, 자리 올림 규칙을 설정하며, 어떤 신호가 예외로 처리되는지 결정하고, 지수의 범위를 제한합니다.
각 스레드는 자신만의 현재 컨텍스트를 가지는데, getcontext()
와 setcontext()
함수를 사용하여 액세스하거나 변경합니다:
-
decimal.
getcontext
()¶ 활성 스레드의 현재 컨텍스트를 돌려줍니다.
-
decimal.
setcontext
(c)¶ 활성 스레드의 현재 컨텍스트를 c 로 설정합니다.
또한 with
문과 localcontext()
함수를 사용하여 활성 컨텍스트를 일시적으로 변경할 수 있습니다.
-
decimal.
localcontext
(ctx=None)¶ with-문으로 진입할 때 활성 스레드의 현재 컨텍스트를 ctx 의 복사본으로 설정하고, with-문을 빠져나올 때 이전의 컨텍스트를 복원하는 컨텍스트 관리자를 돌려줍니다. 컨텍스트를 지정하지 않으면 현재 컨텍스트의 복사본이 사용됩니다.
예를 들어, 다음 코드는 현재 십진 정밀도를 42자리로 설정하고, 계산을 수행한 다음, 이전 컨텍스트를 자동으로 복원합니다:
from decimal import localcontext with localcontext() as ctx: ctx.prec = 42 # 높은 정밀도 계산을 수행합니다 s = calculate_something() s = +s # 최종 결과를 기본 정밀도로 되돌립니다
아래에 설명된 Context
생성자를 사용하여 새로운 컨텍스트를 만들 수도 있습니다. 또한, 이 모듈은 세 가지 미리 만들어진 컨텍스트를 제공합니다:
-
class
decimal.
BasicContext
¶ 이것은 일반 십진 산술 명세에서 정의된 표준 컨텍스트입니다. 정밀도는 9로 설정됩니다. 자리 올림은
ROUND_HALF_UP
으로 설정됩니다. 모든 플래그가 지워집니다. 모든 트랩은Inexact
,Rounded
,Subnormal
을 제외하고는 활성화됩니다 (예외로 처리됩니다).많은 트랩이 활성화되었으므로, 이 컨텍스트는 디버깅에 유용합니다.
-
class
decimal.
ExtendedContext
¶ 이것은 일반 십진 산술 명세에서 정의된 표준 컨텍스트입니다. 정밀도는 9로 설정됩니다. 자리 올림은
ROUND_HALF_EVEN
으로 설정됩니다. 모든 플래그가 지워집니다. 아무 트랩도 활성화되지 않습니다 (그래서 계산 중에 예외가 발생하지 않습니다).트랩이 비활성화되었으므로, 이 컨텍스트는 예외를 발생시키기보다
NaN
이나Infinity
의 결괏값을 선호하는 응용 프로그램에 유용합니다. 이는 응용 프로그램이 그렇지 않으면 프로그램을 중단시킬 수 있는 조건이 있는 경우에도 실행을 완료할 수 있도록 합니다.
-
class
decimal.
DefaultContext
¶ 이 컨텍스트는 새로운 컨텍스트의 프로토타입으로
Context
생성자에 의해 사용됩니다. 필드(가령 정밀도)를 변경하면Context
생성자에 의해 생성된 새로운 컨텍스트에 대한 기본값을 변경하는 효과가 있습니다.이 컨텍스트는 다중 스레드 환경에서 가장 유용합니다. 스레드가 시작되기 전에 필드 중 하나를 변경하면 시스템 전체의 기본값을 설정하는 효과가 있습니다. 스레드가 시작된 후에 필드를 변경하는 것은. 스레드 동기화를 통해 경쟁 조건을 방지해야 하므로 권장되지 않습니다.
단일 스레드 환경에서는, 이 컨텍스트를 아예 사용하지 않는 것이 좋습니다. 대신, 아래에 설명된 대로 명시적으로 컨텍스트를 만드십시오.
기본값은
prec
=28
,rounding
=ROUND_HALF_EVEN
이고Overflow
,InvalidOperation
,DivisionByZero
트랩이 활성화됩니다.
3개의 제공된 컨텍스트 외에도, 새로운 컨텍스트를 Context
생성자를 사용하여 만들 수 있습니다.
-
class
decimal.
Context
(prec=None, rounding=None, Emin=None, Emax=None, capitals=None, clamp=None, flags=None, traps=None)¶ 새로운 컨텍스트를 만듭니다. 필드가 지정되지 않았거나
None
이면, 기본값은DefaultContext
에서 복사됩니다. flags 필드가 지정되지 않았거나None
이면, 모든 플래그가 지워집니다.prec 는 컨텍스트에서 산술 연산의 정밀도를 설정하는 [
1
,MAX_PREC
] 범위의 정수입니다.rounding 옵션은 자리 올림 모드 섹션에 나열된 상수 중 하나입니다.
traps 과 flags 필드는 설정할 신호를 나열합니다. 일반적으로, 새 컨텍스트는 트랩만 설정하고 플래그는 지워진 채로 두어야 합니다.
Emin 과 Emax 필드는 지수에 허용되는 한계를 지정하는 정수입니다. Emin 은 [
MIN_EMIN
,0
], Emax 는 [0
,MAX_EMAX
] 범위 내에 있어야 합니다.capitals 필드는
0
또는1
(기본값)입니다.1
로 설정하면, 지수는 대문자E
와 함께 인쇄됩니다; 그렇지 않으면 소문자e
가 사용됩니다:Decimal('6.02e+23')
.clamp 필드는
0
(기본값) 또는1
입니다.1
로 설정하면, 이 컨텍스트에서 표현할 수 있는Decimal
인스턴스의 지수e
는Emin - prec + 1 <= e <= Emax - prec + 1
입니다. clamp 가0
이면 더 약한 조건이 유지됩니다:Decimal
인스턴스의 조정된 최대Emax
입니다. clamp 가1
일 때, 큰 정상 수는, 가능할 때, 지수 제약 조건을 맞추기 위해 지수가 감소하고 해당 숫자만큼의 0이 계수에 더해집니다; 이것은 수의 값을 보존하지만 유효한 후미 0에 대한 정보를 잃어버립니다. 예를 들면:>>> Context(prec=6, Emax=999, clamp=1).create_decimal('1.23e999') Decimal('1.23000E+999')
flowdas
지수가
Emax - prec + 1
, 즉 994 로 줄어든다는 뜻입니다. 이 지수에 맞추기 위해 세 개의 0을 추가했습니다:>>> Decimal('1.23000E+999').as_tuple() DecimalTuple(sign=0, digits=(1, 2, 3, 0, 0, 0), exponent=994)
1
의 clamp 값은 IEEE 754에 명시된 고정 폭 십진수 교환 형식과 호환되도록 합니다.Context
클래스는 주어진 컨텍스트에서 직접 산술을 하는데 필요한 다수의 메서드뿐만 아니라 여러 가지 범용 메서드를 정의합니다. 이에 더해, 위에서 설명한Decimal
메서드마다 (adjusted()
와as_tuple()
메서드는 예외입니다) 대응하는Context
메서드가 있습니다. 예를 들어,Context
인스턴스C
와Decimal
인스턴스x
에 대해서,C.exp(x)
는x.exp(context=C)
와 동등합니다. 각각Context
메서드는 Decimal 인스턴스가 받아들여지는 곳 어디에서나 파이썬 정수(int
의 인스턴스)를 받아들입니다.-
clear_flags
()¶ 모든 플래그를
0
으로 재설정합니다.
-
clear_traps
()¶ 모든 트랩을
0
으로 재설정합니다.버전 3.3에 추가.
-
copy
()¶ 컨텍스트의 복사본을 돌려줍니다.
-
copy_decimal
(num)¶ Decimal 인스턴스 num의 복사본을 반환합니다.
-
create_decimal
(num)¶ self 를 컨텍스트로 사용해서, num 으로 새 Decimal 인스턴스를 만듭니다.
Decimal
생성자와 달리, 컨텍스트 정밀도, 자리 올림 방법, 플래그 및 트랩이 변환에 적용됩니다.이는 상수가 보통 응용 프로그램에 필요한 것보다 더 큰 정밀도로 제공되기 때문에 유용합니다. 또 다른 이점은 자리 올림이 현재 정밀도를 초과하는 자릿수로 인한 의도하지 않은 결과를 즉시 제거한다는 것입니다. 다음 예제에서, 자리 올림 되지 않은 입력을 사용한다는 것은 합계에 0을 추가하면 결과가 달라질 수 있음을 의미합니다.:
>>> getcontext().prec = 3 >>> Decimal('3.4445') + Decimal('1.0023') Decimal('4.45') >>> Decimal('3.4445') + Decimal(0) + Decimal('1.0023') Decimal('4.44')
flowdas
정밀도가 3인 컨텍스트에서 유효숫자가 5자리인 상수들로 산술을 하고 있습니다. 첫 번째 산술은
Decimal('4.4468')
을 유효숫자 3개로 자리 올림해서Decimal('4.45')
가 얻어집니다. 하지만 두 번째 산술은Decimal('3.4445') + Decimal(0)
이 먼저Decimal('3.4445')
를 주고 이 값은 다시Decimal('3.44')
로 자리 올림됩니다. 이 값이 다시Decimal('1.0023')
와 더해지면Decimal('4.4423')
을 거쳐Decimal('4.44')
로 자리 올림됩니다. 중간 자리 올림 때문에Decimal(0)
을 더하는 것 만으로 두 결과가 달라집니다. 일관된 결과를 얻으려면 상수들을create_decimal()
로 미리 변환해서 사용하라는 뜻입니다.이 메서드는 IBM 명세의 to-number 연산을 구현합니다. 인자가 문자열이면, 선행 또는 후행 공백이나 밑줄이 허용되지 않습니다.
-
create_decimal_from_float
(f)¶ float f 로 새 Decimal 인스턴스를 만들지만, self 를 컨텍스트로 사용하여 자리 올림 합니다.
Decimal.from_float()
클래스 메서드와는 달리, 컨텍스트 정밀도, 자리 올림 방법, 플래그 및 트랩이 변환에 적용됩니다.>>> context = Context(prec=5, rounding=ROUND_DOWN) >>> context.create_decimal_from_float(math.pi) Decimal('3.1415') >>> context = Context(prec=5, traps=[Inexact]) >>> context.create_decimal_from_float(math.pi) Traceback (most recent call last): ... decimal.Inexact: None
버전 3.1에 추가.
-
Etop
()¶ Emax - prec + 1
과 같은 값을 반환합니다.
십진수로 작업하는 일반적인 접근법은
Decimal
인스턴스를 생성한 다음 활성 스레드의 현재 컨텍스트 내에서 진행되는 산술 연산을 적용하는 것입니다. 다른 방법은 특정 컨텍스트 내에서 계산하기 위해 컨텍스트 메서드를 사용하는 것입니다. 메서드는Decimal
클래스의 메서드와 비슷하며 여기에서는 간단히 설명합니다.flowdas
여기에 나오는 설명은 대단히 축약된 것입니다. 사용하기 전에 대응하는
Decimal
메서드의 설명을 확인하세요.-
abs
(x)¶ x 의 절댓값을 돌려줍니다.
-
add
(x, y)¶ x 와 y 의 합을 돌려줍니다.
-
canonical
(x)¶ 같은 Decimal 객체 x 를 반환합니다.
-
compare
(x, y)¶ x 와 y 를 수치로 비교합니다.
-
compare_signal
(x, y)¶ 두 피연산자의 값을 수치로 비교합니다.
-
compare_total
(x, y)¶ 추상 표현을 사용하여 두 피연산자를 비교합니다.
-
compare_total_mag
(x, y)¶ 부호를 무시하고, 추상 표현을 사용하여 두 피연산자를 비교합니다.
-
copy_abs
(x)¶ 부호가 0으로 설정되어있는 x 의 복사본을 돌려줍니다.
-
copy_negate
(x)¶ 부호가 반전된 x 복사본을 반환합니다.
-
copy_sign
(x, y)¶ y 에서 x 로 부호를 복사합니다.
-
divide
(x, y)¶ x 를 y 로 나눈 값을 반환합니다.
-
divide_int
(x, y)¶ x 를 y 로 나눈 후 정수로 잘라낸 값을 반환합니다.
-
exp
(x)¶ e ** x를 반환합니다.
-
fma
(x, y, z)¶ x 에 y 를 곱한 후 z 를 더한 값을 반환합니다.
-
is_canonical
(x)¶ x 가 규범적일 경우
True
를 반환합니다; 그렇지 않으면False
를 반환합니다.
-
is_finite
(x)¶ x 가 유한이면
True
를 반환합니다; 그렇지 않으면False
를 반환합니다.
-
is_infinite
(x)¶ x 가 무한대면
True
를 반환합니다; 그렇지 않으면False
를 반환합니다.
-
is_nan
(x)¶ x 가 qNaN 이나 sNaN 이면
True
를 반환합니다; 그렇지 않으면False
를 반환합니다.
-
is_normal
(x)¶ x 가 정상 수면
True
를 반환합니다; 그렇지 않으면False
를 반환합니다.
-
is_qnan
(x)¶ x 가 조용한 NaN이면
True
를 반환합니다; 그렇지 않으면False
를 반환합니다.
-
is_signed
(x)¶ x 가 음수면
True
를 반환합니다; 그렇지 않으면False
를 반환합니다.
-
is_snan
(x)¶ x 가 신호를 주는 NaN 이면
True
를 반환합니다; 그렇지 않으면False
를 반환합니다.
-
is_subnormal
(x)¶ x 가 비정상이면
True
를 반환합니다; 그렇지 않으면False
를 반환합니다.
-
is_zero
(x)¶ x 가 0이면
True
를 반환합니다; 그렇지 않으면False
를 반환합니다.
-
ln
(x)¶ x 의 자연로그(밑 e)를 반환합니다.
-
log10
(x)¶ x 의 상용로그를 반환합니다.
-
logb
(x)¶ 피연산자의 최상위 유효 숫자의 크기의 지수를 반환합니다.
-
logical_and
(x, y)¶ 각 피연산자의 자릿수별로 논리적 연산 and 를 적용합니다.
-
logical_invert
(x)¶ x 의 모든 자릿수를 반전합니다.
-
logical_or
(x, y)¶ 각 피연산자의 자릿수별로 논리적 연산 or 를 적용합니다.
-
logical_xor
(x, y)¶ 각 피연산자의 자릿수별로 논리적 연산 xor 를 적용합니다.
-
max
(x, y)¶ 두 값을 수치로 비교해, 최댓값을 돌려줍니다.
-
max_mag
(x, y)¶ 부호를 무시하고 값을 수치로 비교합니다.
-
min
(x, y)¶ 두 값을 수치로 비교해, 최솟값을 돌려줍니다.
-
min_mag
(x, y)¶ 부호를 무시하고 값을 수치로 비교합니다.
-
minus
(x)¶ minus는 파이썬에서 단항 접두사 빼기 연산자에 해당합니다.
-
multiply
(x, y)¶ x 와 y 의 곱을 반환합니다.
-
next_minus
(x)¶ x 보다 작고 표현 가능한 가장 큰 수를 반환합니다.
-
next_plus
(x)¶ x 보다 크고 표현 가능한 가장 작은 수를 반환합니다.
-
next_toward
(x, y)¶ y 방향으로 x 에 가장 가까운 숫자를 반환합니다.
-
normalize
(x)¶ x 를 가장 간단한 형태로 환원합니다.
-
number_class
(x)¶ x 의 클래스를 가리키는 문자열을 돌려줍니다.
-
plus
(x)¶ plus는 파이썬에서 단항 접두사 더하기 연산자에 해당합니다. 이 연산은 컨텍스트 정밀도와 자리 올림을 적용하므로 항등 연산이 아닙니다.
-
power
(x, y, modulo=None)¶ x
의y
거듭제곱을 돌려줍니다. 주어지면modulo
모듈로로 환원합니다.두 인자로는
x**y
를 계산합니다.x
가 음수면y
는 정수여야 합니다.y
가 정수이고 결과가 유한하고 'precision' 자릿수로 정확하게 표현될 수 있지 않은 이상 결과는 부정확합니다. 컨텍스트의 자리 올림 모드가 사용됩니다. 결과는 항상 파이썬 버전에서 정확하게 자리 올림 됩니다.Decimal(0) ** Decimal(0)
은InvalidOperation
이 되며,InvalidOperation
가 트랩 되지 않으면,Decimal('NaN')
이 됩니다.버전 3.3에서 변경: C 모듈은 올바르게 자리 올림 된
exp()
와ln()
함수로power()
를 계산합니다. 결과는 잘 정의되어 있지만 "거의 항상 올바르게 자리 올림 될" 뿐입니다.flowdas
C 버전은
x**y
를exp(y * ln(x))
의 형태로 계산한다는 뜻입니다. 이 과정에서 중간 자리 올림이 발생할 수 있는데, 언제나 올바르게 자리 올림된다는 보장은 없다는 뜻입니다.세 인자로는
(x**y) % modulo
를 계산합니다. 세 인자 형식의 경우, 인자에 다음과 같은 제한이 있습니다:세 인자는 모두 정수여야 합니다.
y
는 음수가 아니어야 합니다.x
나y
중 적어도 하나는 0이 아니어야 합니다modulo
는 0이 아니고 최대 'precision' 자릿수를 가져야 합니다
Context.power(x, y, modulo)
의 결괏값은 무한 정밀도로(x**y) % modulo
를 계산할 때 얻을 수 있는 값과 같지만, 더 효율적으로 계산됩니다. 결과의 지수는x
,y
및modulo
의 지수와 관계없이 0입니다. 결과는 항상 정확합니다.
-
quantize
(x, y)¶ y 의 지수를 가지는 (자리 올림 된) x 와 같은 값을 반환합니다.
-
radix
()¶ Decimal이기 때문에 단지 10을 반환합니다, :)
-
remainder
(x, y)¶ 정수 나눗셈의 나머지를 반환합니다.
결과가 0이 아닐 때, 결과의 부호는 원래의 피제수와 같습니다.
-
remainder_near
(x, y)¶ x - y * n
을 반환하는데, n 은x / y
의 정확한 값에 가장 가까운 정수입니다 (결과가 0이면 그 부호는 x 의 부호가 됩니다).
-
rotate
(x, y)¶ x 를 y 번 회전한 복사본을 반환합니다.
-
same_quantum
(x, y)¶ 두 피연산자의 지수가 같으면
True
를 반환합니다.
-
scaleb
(x, y)¶ 첫 번째 피연산자의 지수에 두 번째 값을 더해서 반환합니다.
-
shift
(x, y)¶ x 를 y 번 이동한 복사본을 반환합니다.
-
sqrt
(x)¶ 음이 아닌 수의 제곱근을 컨텍스트의 정밀도로 반환합니다.
-
subtract
(x, y)¶ x 와 y 의 차를 돌려줍니다.
-
to_eng_string
(x)¶ 문자열로 변환합니다. 지수가 필요하면 공학 표기법을 사용합니다.
공학 표기법의 지수는 3의 배수입니다. 이렇게 하면 소수점 왼쪽에 최대 3자리를 남기게 되고, 하나나 두 개의 후행 0을 추가해야 할 수 있습니다.
-
to_integral_exact
(x)¶ 정수로 자리 올림 합니다.
-
to_sci_string
(x)¶ 과학 표기법을 사용하여 숫자를 문자열로 변환합니다.
-
상수¶
이 절의 상수는 C 모듈에서만 의미가 있습니다. 호환성을 위해 순수 파이썬 버전에도 포함되어 있습니다.
32-비트 |
64-비트 |
|
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
-
decimal.
HAVE_THREADS
¶ 값은
True
입니다. 이제 파이썬에는 항상 스레드가 있기 때문에, 폐지되었습니다.
버전 3.9부터 폐지.
-
decimal.
HAVE_CONTEXTVAR
¶ 기본값은
True
입니다. 파이썬이--without-decimal-contextvar
로 컴파일되면, C 버전은 코루틴 로컬 컨텍스트 대신 스레드 로컬을 사용하며 값은False
입니다. 일부 중첩된 컨텍스트 시나리오에서는 약간 더 빠릅니다.
버전 3.9에 추가: 3.7과 3.8로 역 이식되었습니다.
자리 올림 모드¶
-
decimal.
ROUND_CEILING
¶ Infinity
를 향해 올립니다.
-
decimal.
ROUND_DOWN
¶ 0을 향해 자리 올림 합니다.
-
decimal.
ROUND_FLOOR
¶ -Infinity
를 향해 내립니다.
-
decimal.
ROUND_HALF_DOWN
¶ 가장 가까운 값으로 반올림하고, 동률이면 0에서 가까운 것을 선택합니다.
-
decimal.
ROUND_HALF_EVEN
¶ 가장 가까운 값으로 반올림하고, 동률이면 짝수를 선택합니다.
-
decimal.
ROUND_HALF_UP
¶ 가장 가까운 값으로 반올림하고, 동률이면 0에서 먼 것을 선택합니다.
-
decimal.
ROUND_UP
¶ 0에서 먼 쪽으로 자리 올림 합니다.
-
decimal.
ROUND_05UP
¶ 0을 향해 자리 올림 했을 때 마지막 숫자가 0이나 5면 0에서 먼 쪽으로 자리 올림 합니다. 그렇지 않으면 0을 향해 자리 올림 합니다.
신호¶
신호는 계산 중 발생하는 조건을 나타냅니다. 각각은 하나의 컨텍스트 플래그와 하나의 컨텍스트 트랩 활성화기에 대응합니다.
컨텍스트 플래그는 조건이 발생할 때마다 설정됩니다. 계산 후에, 플래그는 정보를 얻기 위한 목적으로 확인될 수 있습니다 (예를 들어, 계산이 정확한지를 판별하기 위해). 플래그를 확인한 후 다음 계산을 시작하기 전에 모든 플래그를 지우십시오.
컨텍스트의 트랩 활성화기가 신호에 대해 설정되면, 조건은 파이썬 예외를 일으킵니다. 예를 들어, DivisionByZero
트랩이 설정되면, 이 조건을 만날 때 DivisionByZero
예외가 발생합니다.
-
class
decimal.
Clamped
¶ 표현 제약 조건에 맞도록 지수를 변경했습니다.
일반적으로, 지수가 컨텍스트의
Emin
과Emax
한계를 벗어날 때 클램핑이 발생합니다. 가능하면, 계수에 0을 추가하여 지수를 줄입니다.
-
class
decimal.
DecimalException
¶ 다른 신호의 베이스 클래스이고
ArithmeticError
의 서브 클래스입니다.
-
class
decimal.
DivisionByZero
¶ 무한대가 아닌 숫자를 0으로 나눴다는 신호를 줍니다.
나눗셈, 모듈로 나눗셈 또는 음수로 숫자를 거듭제곱할 때 발생할 수 있습니다. 이 신호가 트랩 되지 않으면, 계산에 제공된 입력의 부호에 따라
Infinity
나-Infinity
를 돌려줍니다.
-
class
decimal.
Inexact
¶ 자리 올림이 발생했고 결과가 정확하지 않음을 나타냅니다.
자리 올림 도중 0이 아닌 숫자가 삭제된 경우 신호를 줍니다. 자리 올림 된 결과가 반환됩니다. 신호 플래그나 트랩은 결과가 정확하지 않을 때를 감지하는 데 사용됩니다.
-
class
decimal.
InvalidOperation
¶ 유효하지 않은 연산이 수행되었습니다.
의미가 없는 연산이 요청되었음을 나타냅니다. 트랩 되지 않으면,
NaN
을 반환합니다. 가능한 원인은 다음과 같습니다:Infinity - Infinity 0 * Infinity Infinity / Infinity x % 0 Infinity % x sqrt(-x) and x > 0 0 ** 0 x ** (non-integer) x ** Infinity
flowdas
정수가 아닌 값이나 무한대로 거듭제곱하는 경우는
x
가 음수일 때만 해당됩니다. 정수가 아닌 값으로 음수를 거듭제곱하면 복소수가 되고, 무한대로-1
보다 작거나 같은 음수를 거듭제곱하면 부호가 결정되지 않기 때문입니다.-1
보다 큰 음수를 무한대로 거듭제곱하면0
이지만, 이 경우도InvalidOperation
신호를 줍니다.
-
class
decimal.
Overflow
¶ 수치적 오버플로.
자리 올림 후에 지수가
Emax
보다 큼을 나타냅니다. 트랩 되지 않으면, 결과는 자리 올림 모드에 따라 달라지는데, 가장 큰 표현 가능한 유한 수로 안쪽으로 당기거나Infinity
를 향해 바깥쪽으로 자리 올림 됩니다. 두 경우 모두Inexact
와Rounded
신호도 줍니다.
-
class
decimal.
Rounded
¶ 정보가 손실되지는 않았지만 자리 올림이 발생했습니다.
자리 올림이 자릿수를 버릴 때마다 신호를 줍니다; 그 자릿수가 0일 때도 그렇습니다 (가령
5.00
을5.0
으로 자리 올림). 트랩 되지 않으면, 결과를 그대로 반환합니다. 이 신호는 유효숫자의 손실을 감지하는 데 사용됩니다.
-
class
decimal.
Subnormal
¶ 자리 올림 전에 지수가
Emin
보다 작습니다.연산 결과가 비정상(지수가 너무 작음)일 때 발생합니다. 트랩 되지 않으면, 결과를 그대로 반환합니다.
-
class
decimal.
Underflow
¶ 결과가 0으로 자리 올림 되는 수치적 언더플로.
자리 올림에 의해 비정상 결과가 0으로 밀릴 때 발생합니다.
Inexact
와Subnormal
신호도 줍니다.
-
class
decimal.
FloatOperation
¶ float와 Decimal을 혼합하는 데 더 엄격한 의미를 사용합니다.
신호가 트랩되지 않으면 (기본값),
Decimal
생성자,create_decimal()
및 모든 비교 연산자에서 float와 Decimal을 혼합 할 수 있습니다. 변환과 비교 모두 정확합니다. 복합 연산의 발생은 컨텍스트 플래그에FloatOperation
을 설정하여 조용히 기록됩니다.from_float()
나create_decimal_from_float()
를 사용한 명시적 변환은 플래그를 설정하지 않습니다.그렇지 않으면 (신호가 트랩되면), 같음 비교와 명시적 변환만 조용히 수행됩니다. 다른 모든 혼합된 연산은
FloatOperation
을 발생시킵니다.
다음 표는 신호의 계층 구조를 요약한 것입니다:
exceptions.ArithmeticError(exceptions.Exception)
DecimalException
Clamped
DivisionByZero(DecimalException, exceptions.ZeroDivisionError)
Inexact
Overflow(Inexact, Rounded)
Underflow(Inexact, Rounded, Subnormal)
InvalidOperation
Rounded
Subnormal
FloatOperation(DecimalException, exceptions.TypeError)
부동 소수점 노트¶
증가시킨 정밀도로 자리 올림 오차 줄이기¶
십진 부동 소수점을 사용하면 십진수 표현 오차가 없어집니다 (0.1
을 정확히 나타낼 수 있습니다); 그러나 0이 아닌 숫자가 고정된 정밀도를 초과할 때 일부 연산은 여전히 자리 올림 오차를 일으킬 수 있습니다.
자리 올림 오차의 효과는 거의 상쇄되는 양을 더하거나 빼는 것에 의해 증폭되어 유효숫자의 손실로 이어질 수 있습니다. Knuth는 불충분한 정밀도로 자리 올림 된 부동 소수점 산술로 인해 덧셈의 결합 법칙과 배분 법칙이 파괴되는 두 가지 사례를 제공합니다:
# Seminumerical Algorithms, 4.2.2 절에서 인용한 예제.
>>> from decimal import Decimal, getcontext
>>> getcontext().prec = 8
>>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111')
>>> (u + v) + w
Decimal('9.5111111')
>>> u + (v + w)
Decimal('10')
>>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003')
>>> (u*v) + (u*w)
Decimal('0.01')
>>> u * (v+w)
Decimal('0.0060000')
flowdas
Seminumerical Algorithms 는 Knuth 의 The Art of Computer Programming 시리즈의 2권입니다. 번역본도 나와 있습니다.
decimal
모듈은 유효숫자의 손실을 피할 수 있을 만큼 정밀도를 확장함으로써 항등 관계를 복구할 수 있게 합니다 :
>>> getcontext().prec = 20
>>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111')
>>> (u + v) + w
Decimal('9.51111111')
>>> u + (v + w)
Decimal('9.51111111')
>>>
>>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003')
>>> (u*v) + (u*w)
Decimal('0.0060000')
>>> u * (v+w)
Decimal('0.0060000')
특수 값¶
decimal
모듈의 수 체계는 NaN
, sNaN
, -Infinity
, Infinity
와 두 개의 0 +0
과 -0
을 포함하는 특수 값을 제공합니다.
무한대는 다음과 같이 직접 생성될 수 있습니다: Decimal('Infinity')
. 또한, DivisionByZero
신호가 트랩 되지 않을 때 0으로 나눠서 발생할 수 있습니다. 마찬가지로, Overflow
신호가 트랩 되지 않을 때, 무한대는 표현 가능한 가장 큰 수의 한계를 넘어서 자리 올림 된 결과가 될 수 있습니다.
무한대는 부호가 있고 (아핀) 산술 연산에 사용될 수 있는데, 매우 크고 불확정적(indeterminate)인 숫자로 취급됩니다. 예를 들어, 무한대에 상수를 더하면 또 다른 무한대를 줍니다.
flowdas
수 체계에서 무한대를 표현하는 두 가지 방법이 있습니다. 하나는 사영 무한(projective infinity)이라는
것으로, 무한대를 부호가 없는 (+가 아니라 아예 부호라는 것이 없는) 것으로 보고 아주 큰 수와 아주 작은 수
모두 하나의 무한대로 표현합니다. 이에 반해 아핀 무한(affine innfinity)이라는 것은 무한대를 부호가
있는 값으로 보고, 아주 큰 수와 아주 작은 수를 두 개의 무한대 (-Infinity
,
Infinity
) 로 따로 표현합니다. decimal
모듈이 따르고 있는 명세는 아핀 무한을
사용합니다.
어떤 연산은 불확정적이고, NaN
을 반환하거나, InvalidOperation
신호가 트랩 되면, 예외를 발생시킵니다. 예를 들어, 0/0
은 "숫자가 아님(not a number)"을 의미하는 NaN
을 반환합니다. 이 종류의 NaN
은 조용하고, 한 번 만들어지면 다른 연산에 포함될 때 항상 다른 NaN
을 생성합니다. 이 동작은 때때로 빠진 입력이 있는 일련의 계산에 유용할 수 있습니다 --- 특정 결과를 잘못된 것으로 표시하면서 계산을 진행할 수 있도록 합니다.
다른 종류는 sNaN
인데, 모든 연산 후에 조용히 남아 있는 대신 신호를 줍니다. 이것은 유효하지 않은 결과가 특수한 처리를 위해 계산을 중단시켜야 할 때 유용한 반환 값입니다.
파이썬의 비교 연산자의 동작은 NaN
이 관련되어있을 때 약간 의외일 수 있습니다. 피연산자 중 하나가 조용하거나 신호를 주는 NaN
일 때, 같음 검사는 항상 False
를 반환하고 (심지어 Decimal('NaN')==Decimal('NaN')
조차도), 다름 검사는 항상 True
를 반환합니다. <
, <=
, >
또는 >=
연산자 중 하나를 사용하여 두 Decimal을 비교하려는 시도는 피연산자 중 어느 것이 든 NaN
이면 InvalidOperation
신호를 발생시킵니다. 이 신호가 트랩 되지 않으면 False
를 반환합니다. 일반 십진 산술 명세는 직접 비교의 동작을 명시하지 않습니다; NaN
을 포함하는 비교를 위한 이러한 규칙은 IEEE 854 표준(섹션 5.7의 표 3을 보세요)에서 가져온 것입니다. 엄격한 표준 준수를 위해서는, 대신 compare()
및 compare-signal()
메서드를 사용하십시오.
부호 있는 0은 언더플로 하는 계산의 결과일 수 있습니다. 계산을 더 정밀하게 수행한다면 얻게 될 결과의 기호를 유지합니다. 크기가 0이기 때문에, 양과 음의 0은 같다고 취급되며 부호는 정보 용입니다.
서로 다른 부호를 갖는 부호 있는 0이 같은 것에 더해, 여전히 동등한 값이지만 다른 정밀도를 갖는 여러 표현이 존재합니다. 익숙해지는데 약간 시간이 필요합니다. 정규화된 부동 소수점 표현에 익숙한 사람들에게는, 다음 계산이 0과 같은 값을 반환한다는 것이 즉시 명백하지는 않습니다:
>>> 1 / Decimal('Infinity')
Decimal('0E-1000026')
스레드로 작업하기¶
getcontext()
함수는 스레드마다 다른 Context
객체에 접근합니다. 별도의 스레드 컨텍스트를 갖는다는 것은 스레드가 다른 스레드를 방해하지 않고 변경할 수 있음을 의미합니다 (가령 getcontext().prec=10
).
마찬가지로, setcontext()
함수는 자동으로 대상을 현재 스레드에 할당합니다.
setcontext()
가 getcontext()
전에 호출되지 않았다면, getcontext()
는 현재 스레드에서 사용할 새로운 컨텍스트를 자동으로 생성합니다.
새 컨텍스트는 DefaultContext 라는 프로토타입 컨텍스트에서 복사됩니다. 각 스레드가 응용 프로그램 전체에서 같은 값을 사용하도록 기본값을 제어하려면, DefaultContext 객체를 직접 수정하십시오. getcontext()
를 호출하는 스레드 사이에 경쟁 조건이 없도록, 어떤 스레드가 시작되기 전에 수행되어야 합니다. 예를 들면:
# 시작될 모든 스레드에 대해 응용 프로그램 전체 기본값을 설정합니다
DefaultContext.prec = 12
DefaultContext.rounding = ROUND_DOWN
DefaultContext.traps = ExtendedContext.traps.copy()
DefaultContext.traps[InvalidOperation] = 1
setcontext(DefaultContext)
# 그런 다음, 스레드를 시작할 수 있습니다
t1.start()
t2.start()
t3.start()
. . .
조리법¶
다음은 유틸리티 함수로 사용되고 Decimal
클래스로 작업하는 방법을 보여주는 몇 가지 조리법입니다:
def moneyfmt(value, places=2, curr='', sep=',', dp='.',
pos='', neg='-', trailneg=''):
"""Decimal을 화폐 형식 문자열로 변환합니다.
places: 필수적, 소수점 뒤로 필요한 자릿수
curr: 선택적, 부호 앞에 오는 통화 기호 (비어있어도 됩니다)
sep: 선택적, 자리수 구분자 (콤마, 마침표, 스페이스, 또는 빈문자열)
dp: 소수점 (콤마나 마침표)
places 가 0 일 때만 빈문자열로 지정하세요
pos: 선택적, 양수를 위한 부호: '+', 스페이스 또는 빈문자열
neg: 선택적, 음수를 위한 부호: '-', '(', 스페이스 또는 빈문자열
trailneg:선택적, 후행 음수 표시: '-', ')', 스페이스 또는 빈문자열
>>> d = Decimal('-1234567.8901')
>>> moneyfmt(d, curr='$')
'-$1,234,567.89'
>>> moneyfmt(d, places=0, sep='.', dp='', neg='', trailneg='-')
'1.234.568-'
>>> moneyfmt(d, curr='$', neg='(', trailneg=')')
'($1,234,567.89)'
>>> moneyfmt(Decimal(123456789), sep=' ')
'123 456 789.00'
>>> moneyfmt(Decimal('-0.02'), neg='<', trailneg='>')
'<0.02>'
"""
q = Decimal(10) ** -places # 2 places --> '0.01'
sign, digits, exp = value.quantize(q).as_tuple()
result = []
digits = list(map(str, digits))
build, next = result.append, digits.pop
if sign:
build(trailneg)
for i in range(places):
build(next() if digits else '0')
if places:
build(dp)
if not digits:
build('0')
i = 0
while digits:
build(next())
i += 1
if i == 3 and digits:
i = 0
build(sep)
build(curr)
build(neg if sign else pos)
return ''.join(reversed(result))
def pi():
"""현재 정밀도로 Pi 를 계산합니다.
>>> print(pi())
3.141592653589793238462643383
"""
getcontext().prec += 2 # 중단 단계를 위한 추가의 유효숫자
three = Decimal(3) # 일반 float 에 사용하려면 "three=3.0" 로 치환하세요
lasts, t, s, n, na, d, da = 0, three, 3, 1, 0, 0, 24
while s != lasts:
lasts = s
n, na = n+na, na+8
d, da = d+da, da+32
t = (t * n) / d
s += t
getcontext().prec -= 2
return +s # 단항 플러스 연산자는 새 정밀도를 적용합니다
def exp(x):
"""e 의 x 제곱을 반환합니다. 결과 형은 입력 형과 일치합니다.
>>> print(exp(Decimal(1)))
2.718281828459045235360287471
>>> print(exp(Decimal(2)))
7.389056098930650227230427461
>>> print(exp(2.0))
7.38905609893
>>> print(exp(2+0j))
(7.38905609893+0j)
"""
getcontext().prec += 2
i, lasts, s, fact, num = 0, 0, 1, 1, 1
while s != lasts:
lasts = s
i += 1
fact *= i
num *= x
s += num / fact
getcontext().prec -= 2
return +s
def cos(x):
"""라디안으로 측정된 x 의 코사인(cosine)을 반환합니다.
테일러 전개 근사법은 x 가 작음 값을 때 잘 작동합니다.
큰 값의 경우, 먼저 x = x % (2 * pi) 를 계산하세요.
>>> print(cos(Decimal('0.5')))
0.8775825618903727161162815826
>>> print(cos(0.5))
0.87758256189
>>> print(cos(0.5+0j))
(0.87758256189+0j)
"""
getcontext().prec += 2
i, lasts, s, fact, num, sign = 0, 0, 1, 1, 1, 1
while s != lasts:
lasts = s
i += 2
fact *= i * (i-1)
num *= x * x
sign *= -1
s += num / fact * sign
getcontext().prec -= 2
return +s
def sin(x):
"""라디안으로 측정된 x 의 사인(sine)을 반환합니다.
테일러 전개 근사법은 x 가 작음 값을 때 잘 작동합니다.
큰 값의 경우, 먼저 x = x % (2 * pi) 를 계산하세요.
>>> print(sin(Decimal('0.5')))
0.4794255386042030002732879352
>>> print(sin(0.5))
0.479425538604
>>> print(sin(0.5+0j))
(0.479425538604+0j)
"""
getcontext().prec += 2
i, lasts, s, fact, num, sign = 1, 0, x, 1, x, 1
while s != lasts:
lasts = s
i += 2
fact *= i * (i-1)
num *= x * x
sign *= -1
s += num / fact * sign
getcontext().prec -= 2
return +s
Decimal FAQ¶
Q. decimal.Decimal('1234.5')
라고 입력하는 것은 귀찮은 일입니다. 대화형 인터프리터를 사용할 때 타자를 최소화할 방법이 있습니까?
A. 일부 사용자는 생성자를 하나의 문자로 축약합니다:
>>> D = decimal.Decimal
>>> D('1.23') + D('3.45')
Decimal('4.68')
Q. 소수점 두 자리의 고정 소수점 응용 프로그램에서, 일부 입력에 여러 자리가 있고 자리 올림 해야 합니다. 어떤 것은 여분의 자릿수가 없다고 가정되지만, 유효성 검사가 필요합니다. 어떤 방법을 사용해야 합니까?
A. quantize()
메서드는 고정된 소수 자릿수로 자리 올림 합니다. Inexact
트랩이 설정되면, 유효성 검사에도 유용합니다:
>>> TWOPLACES = Decimal(10) ** -2 # Decimal('0.01') 과 같습니다
>>> # 두 자리로 자리 올림합니다
>>> Decimal('3.214').quantize(TWOPLACES)
Decimal('3.21')
>>> # 숫자가 두 자리를 넘지 않는지 확인합니다
>>> Decimal('3.21').quantize(TWOPLACES, context=Context(traps=[Inexact]))
Decimal('3.21')
>>> Decimal('3.214').quantize(TWOPLACES, context=Context(traps=[Inexact]))
Traceback (most recent call last):
...
Inexact: None
Q. 일단 유효한 두 자리 입력이 있으면, 응용 프로그램 전체에서 해당 불변성을 어떻게 유지합니까?
A. 정수로 더하기, 빼기 및 곱하기와 같은 일부 연산은 고정 소수점을 자동으로 보존합니다. 나눗셈과 정수가 아닌 수로 곱하는 것과 같은 다른 연산은, 소수점 이하 자릿수를 바꿀 것이고, 뒤에 quantize()
단계를 적용할 필요가 있습니다:
>>> a = Decimal('102.72') # 초기 고정 소수점 값
>>> b = Decimal('3.17')
>>> a + b # 덧셈은 고정 소수점을 보존합니다
Decimal('105.89')
>>> a - b
Decimal('99.55')
>>> a * 42 # 정수로 곱하는 것도 마찬가지입니다
Decimal('4314.24')
>>> (a * b).quantize(TWOPLACES) # 정수가 아닌 수로 곱할 때는 quantize 해야만 합니다
Decimal('325.62')
>>> (b / a).quantize(TWOPLACES) # 나눗셈도 quantize 해야 합니다
Decimal('0.03')
고정 소수점 응용 프로그램을 개발할 때, quantize()
단계를 처리하는 함수를 정의하는 것이 편리합니다:
>>> def mul(x, y, fp=TWOPLACES):
... return (x * y).quantize(fp)
>>> def div(x, y, fp=TWOPLACES):
... return (x / y).quantize(fp)
>>> mul(a, b) # 자동적으로 고정 소수점을 보존합니다
Decimal('325.62')
>>> div(b, a)
Decimal('0.03')
Q. 같은 값을 표현하는 여러 가지 방법이 있습니다. 숫자 200
, 200.000
, 2E2
, 그리고 02E+4
는 모두 다양한 정밀도로 같은 값을 가집니다. 이것들은 단일하게 인식할 수 있는 표준적인 값으로 변환할 방법이 있습니까?
A. the normalize()
메서드는 모든 해당 값을 단일 표현으로 매핑합니다:
>>> values = map(Decimal, '200 200.000 2E2 .02E+4'.split())
>>> [v.normalize() for v in values]
[Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2')]
Q. 일부 십진수 값은 항상 지수 표기법으로 인쇄됩니다. 지수가 아닌 표현을 얻을 방법이 있습니까?
A. 일부 값의 경우, 지수 표기법만이 계수에 있는 유효 숫자를 나타낼 수 있습니다. 예를 들어 5.0E+3
을 5000
으로 표현하면 값은 일정하게 유지되지만, 원본의 두 자리 유효숫자를 표시할 수 없습니다.
응용 프로그램이 유효 숫자를 추적하는 데 신경 쓰지 않으면, 지수 및 후행 0을 제거하고 유효숫자를 잃지만, 값이 바뀌지 않도록 하기는 쉽습니다:
>>> def remove_exponent(d):
... return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
>>> remove_exponent(Decimal('5E+3'))
Decimal('5000')
flowdas
remove_exponent
가 언제나 지수 표기법을 사용하지 않는 것은 아닙니다.
Q. 일반 float를 Decimal
로 변환하는 방법이 있습니까?
A. 그렇습니다. 모든 이진 부동 소수점은 Decimal로 정확히 표현될 수 있습니다. 하지만 정확한 변환이 취하는 정밀도는 직관이 제안하는 것보다 더 클 수 있습니다:
>>> Decimal(math.pi)
Decimal('3.141592653589793115997963468544185161590576171875')
Q. 복잡한 계산에서, 정밀도가 부족하거나 자리 올림 이상이 발생하여 엉터리 결과를 얻지는 않았는지 확인하려면 어떻게 해야 합니까?
A. decimal 모듈은 결과를 쉽게 테스트할 수 있게 합니다. 가장 좋은 방법은 더 높은 정밀도와 다양한 자리 올림 모드를 사용하여 계산을 다시 실행하는 것입니다. 크게 다른 결과는 정밀도 부족, 자리 올림 모드 문제, 부적절한 입력 또는 수치가 불안정한 알고리즘을 나타냅니다.
컨텍스트 정밀도가 입력이 아닌 연산 결과에 적용된다는 사실을 확인했습니다. 다른 정밀도의 값을 혼합할 때 주의해야 할 것이 있습니까?
A. 그렇습니다. 원칙은 모든 값이 정확한 것으로 간주하므로 해당 값에 대한 산술도 마찬가지라는 것입니다. 결과 만 자리 올림 됩니다. 입력에 대한 이점은 "입력하는 것이 얻는 것"이라는 것입니다. 단점은 입력값을 자리 올림 하는 것을 잊어버리면 결과가 이상하게 보일 수 있다는 점입니다:
>>> getcontext().prec = 3
>>> Decimal('3.104') + Decimal('2.104')
Decimal('5.21')
>>> Decimal('3.104') + Decimal('0.000') + Decimal('2.104')
Decimal('5.20')
해법은 정밀도를 높이거나 단항 플러스 연산을 사용하여 입력의 자리 올림을 강제 수행하는 것입니다:
>>> getcontext().prec = 3
>>> +Decimal('1.23456789') # 단항 플러스는 자리 올림을 일으킵니다
Decimal('1.23')
다른 방법으로, 입력은 Context.create_decimal()
메서드를 사용하여 생성 시에 자리 올림 될 수 있습니다:
>>> Context(prec=5, rounding=ROUND_DOWN).create_decimal('1.2345678')
Decimal('1.2345')
Q. CPython 구현은 커다란 수에서 빠릅니까?
A. 예. CPython 과 PyPy3 구현에서, decimal 모듈의 C/CFFI 버전은 임의의 정밀도로 올바르게 자리 올림 되는 십진 부동 소수점 산술을 위한 고속 libmpdec 라이브러리를 통합합니다 1. libmpdec
는 중간 크기의 숫자에는 카라추바 곱셈(Karatsuba multiplication)을 사용하고 매우 큰 숫자에는 수론적 변환(Number Theoretic Transform)을 사용합니다.
flowdas
2019년 3월에 David Harvey와 Joris Van Der Hoeven이 마침내 O(n log n) 알고리즘을 발견했습니다. FFT를 사용하는 알고리즘인데, 자세한 내용은 Integer multiplication in time O(n log n) 을 참조하십시오. 이 논문에 관한 배경과 해설을 제공하는 Quanta의 기사 Mathematicians Discover the Perfect Way to Multiply도 참고하시면 좋습니다.
컨텍스트는 정확한 임의 정밀도 산술에 맞게 조정되어야 합니다. Emin
과 Emax
는 항상 최댓값으로 설정해야 하며, clamp
는 항상 0(기본값)이어야 합니다. prec
를 설정하려면 약간의 주의가 필요합니다.
큰 숫자 산술을 시도하는 가장 쉬운 방법은 prec
의 최댓값도 사용하는 것입니다 2:
>>> setcontext(Context(prec=MAX_PREC, Emax=MAX_EMAX, Emin=MIN_EMIN))
>>> x = Decimal(2) ** 256
>>> x / 128
Decimal('904625697166532776746648320380374280103671755200316906558262375061821325312')
부정확한 결과의 경우, 64비트 플랫폼에서 MAX_PREC
는 너무 크고 사용 가능한 메모리가 충분하지 않을 것입니다:
>>> Decimal(1) / 3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
MemoryError
초과 할당(overallocation)이 있는 시스템(예를 들어 리눅스)에서, 더 정교한 접근 방식은 prec
를 사용 가능한 RAM의 양으로 조정하는 것입니다. RAM이 8GB이고 각각 최대 500MB를 사용하는 피연산자 10개가 동시에 있다고 가정합시다:
>>> import sys
>>>
>>> # 8-바이트 워드와 워드 당 19 자릿수로 500MB를 사용하는 단일 피연산자의 최대 자릿수
>>> # (32비트 빌드에서는 4-바이트와 9 자릿수):
>>> maxdigits = 19 * ((500 * 1024**2) // 8)
>>>
>>> # 이것이 동작하는지 확인합니다:
>>> c = Context(prec=maxdigits, Emax=MAX_EMAX, Emin=MIN_EMIN)
>>> c.traps[Inexact] = True
>>> setcontext(c)
>>>
>>> # 사용 가능한 정밀도를 9로 채웁니다:
>>> x = Decimal(0).logical_invert() * 9
>>> sys.getsizeof(x)
524288112
>>> x + 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
decimal.Inexact: [<class 'decimal.Inexact'>]
일반적으로 (그리고 특히 초과 할당이 없는 시스템에서), 더 엄격한 경계를 추정하고 모든 계산이 정확할 것으로 예상되면 Inexact
트랩을 설정하는 것이 좋습니다.