2009-05-31 5 views
8

저는 회사에서 매일 Python 2.4로 작업합니다. 나는 다용도 로그 함수 'log'를 표준 수학 라이브러리에서 사용했고 log (2 ** 31, 2)를 입력했을 때 31.000000000000004를 반환했다.파이썬에서 부정확 한 로그

나는 2의 다른 힘으로 똑같은 일을했으며 완벽하게 작동했습니다. 'log10 (2 ** 31)/log10 (2)'을 실행했고 라운드 31.0을 가졌습니다.

더 진보 된 버전으로 수정되었다고 가정하고 파이썬 3.0.1에서 같은 원래 함수를 실행 해 보았습니다.

왜 이런 일이 발생합니까? 파이썬에서 수학 함수에 약간의 부정확성이있을 수 있습니까?

+0

중복, 누군가 다른 사람이 할 수 있습니다. –

+0

파이썬 3이 부동 소수점 오류를 수정하지 않았 음을 지적해야합니다. 대신 출력 결과는 여유 시간 대신 의도 된 부동 소수점 값을 표시하는 스마트 알고리즘을 사용합니다. –

답변

44

이것은 컴퓨터 계산에서 예상됩니다. 아마도 IEEE 754과 같이 학교에서 배운 수학과 일치하지 않는 특수한 규칙을 따르고 있습니다.

이 실제로 일 경우 Python의 decimal type을 사용하십시오.

예 :

from decimal import Decimal, Context 
ctx = Context(prec=20) 
two = Decimal(2) 
ctx.divide(ctx.power(two, Decimal(31)).ln(ctx), two.ln(ctx)) 
+22

좋은 답변은 +1하지만 대부분이 "실제로 문제가되는 경우"에 대한 답입니다. 프로브는 정확도가 떨어지는 토성으로 비행했습니다. – dwc

+0

실제로. 이탤릭체는 대답의 가장 중요한 부분입니다. –

+0

@dwc OP가 로그 기능의 결과를 가져오고 있다면 그것은 중요했을 것입니다. 그러면 오류가 매우 커집니다. 내 경우에, 내 프로그램 중 하나에서, 나는'a = floor (log (x, b))'라고했고, 프로그램은'floor (log (243,3))'이 나올거야 4 – Rushil

17

항상는 부동 소수점 연산하는 것은 그들에 약간의 오류가 있고 (계정에 해당 오류를 가지고 평등을 확인한다고 가정 중 하나 0.00001 % 등의 비율 값 또는 0.00000000001와 같은 고정 값). 이 부정확성은 모든 십진수가 고정 된 비트 정밀도로 이진수로 표현 될 수있는 것은 아니기 때문에 주어진 것이다.

파이썬이 IEEE754를 사용하는 경우 특별한 단정지가 아닙니다. 31은 단 정밀도로도 쉽게 표현할 수 있어야하기 때문입니다. 그러나 로그의 수를 계산하는 데 걸리는 많은 단계 중 하나에서 정밀도가 떨어질 수도 있습니다. 이는 직접 강도 2와 같은 특별한 경우를 탐지하는 코드가 없기 때문에 로그 을 계산하기 만하면됩니다.

+1

+1 나는 네가 마지막 문장으로 그걸 처리했다고 생각해. –

+0

매우 흥미 롭습니다. 나는 매우 오랫동안 코드를 작성하고 있으며,이 현상을 처음 접하게되었습니다. 그러나 여기에 대한 반응이 있은 후에 나는 그것이 왜 일어 났는지에 대한 더 큰 그림을보기 시작합니다. –

5

부동 소수점 연산은 절대 정확하지 않습니다. 이들은 언어/하드웨어 인프라에 대해 허용 가능한 상대적 오류가있는 결과를 반환합니다.

일반적으로 부동 소수점 연산이 정확하고 특히 단 정밀도라고 가정하는 것은 상당히 잘못되었습니다. "Accuracy problems" section from Wikipedia 부동 소수점 기사 :

2

이것은 정상입니다. log10은 로그의 기본이 정확히 무엇인지를 알기 때문에 log (x, y)가 더 정확할 것으로 기대됩니다. 또한 기본 10 로그를 계산하기위한 하드웨어 지원이있을 수 있습니다.

3

IEEE 더블 부동 소수점 숫자는 52 bits of precision 있습니다. 10^15 < 2^52 < 10^16이므로 두 배의 유효 숫자는 15 ~ 16 자리입니다. 31.000000000000004의 결과는 16 자리 숫자로 정확하므로 예상 한만큼 좋습니다.

1

파이썬에서 숫자의 숫자 (float.__repr__)는 IEEE-754 산술이 최대 한도까지 정확하게 주어진다면 변환 될 때 가능한 한 실제 값에 최대한 가까운 문자열을 반환하려고 시도합니다.당신 print이 결과 에드 경우 어떤 경우에는, 당신은 눈치 채지 못할 거라고 :

>>> from math import log 
>>> log(2**31,2) 
31.000000000000004 
>>> print log(2**31,2) 
31.0 

print 적은 숫자를 표시하여 부정확를 충족시켜하는합니다 (float.__str__ 방법으로,이 경우) 문자열을 인수로 변환 :

>>> log(1000000,2) 
19.931568569324174 
>>> print log(1000000,2) 
19.9315685693 
>>> 1.0/10 
0.10000000000000001 
>>> print 1.0/10 
0.1 

usuallyuseless '대답은 실제로 매우 유용합니다 :) 다년생 부동 소수점 질문 (? 왜 부동 소수점 오류를 얻고있다), 게시 할 최적의 중복 Q를 찾을 수의