플로팅을 평등에 대해 비교하는 것은 반올림 및 정밀도 문제로 인해 약간 미묘한 것으로 잘 알려져 있습니다.
예를 들면 다음과 같습니다.
https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
파이썬에서 이것을 처리하기 위해 권장되는 방법은 무엇입니까?
분명히 어딘가에 표준 라이브러리 기능이 있습니까?
답변
Python 3.5는 PEP 485에 설명 된대로 math.isclose
및 cmath.isclose
기능 을 추가합니다 .
이전 버전의 Python을 사용하는 경우 해당 기능이 documentation에 제공 됩니다.
def isclose(a, b, rel_tol=1e-09, abs_tol=0.0):
return abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
rel_tol
상대 허용 오차이며, 두 인수의 크기가 더 큰 값을 곱합니다. 값이 커질수록 여전히 동일한 것으로 간주하면서 허용되는 차이도 커집니다.
abs_tol
모든 경우에 그대로 적용되는 절대 공차입니다. 차이가 해당 공차 중 하나보다 작 으면 값이 동일한 것으로 간주됩니다.
답변
다음과 같은 간단한 것이 충분하지 않습니까?
return abs(f1 - f2) <= allowed_error
답변
Gareth의 대답이 가벼운 기능 / 솔루션으로 가장 적합 할 것입니다.
그러나 NumPy를 사용 중이거나 고려 중이라면 패키지 기능이 있음을 알면 도움이 될 것이라고 생각했습니다.
numpy.isclose(a, b, rtol=1e-05, atol=1e-08, equal_nan=False)
약간의 면책 조항 : NumPy를 설치하는 것은 플랫폼에 따라 사소한 경험이 될 수 있습니다.
답변
클래스 decimal
를 제공하는 Python 모듈을 사용하십시오 Decimal
.
의견에서 :
수학이 많은 작업을하고 있고 소수점 이하의 정밀도가 절대적으로 필요하지 않으면 실제로 문제가 발생할 수 있습니다. 플로트는 처리하기에 더 빠르지 만 정확하지 않습니다. 십진법은 매우 정확하지만 느립니다.
답변
파이썬 표준 라이브러리 (또는 다른 곳)에서 도슨의 AlmostEqual2sComplement
기능 을 구현하는 것을 알지 못합니다 . 그것이 당신이 원하는 종류의 행동이라면, 당신은 그것을 직접 구현해야합니다. (이 경우 Dawson의 영리한 비트 해킹을 사용하는 것보다 일반적인 형식의 if abs(a-b) <= eps1*(abs(a)+abs(b)) + eps2
유사 테스트를 사용하는 것이 좋습니다 . Dawson과 유사한 동작을 얻으려면 if abs(a-b) <= eps*max(EPS,abs(a),abs(b))
작은 고정형 과 같은 것을 말할 수 있습니다 EPS
. 정확하지는 않습니다. 도슨과 동일하지만 정신은 비슷합니다.
답변
부동 소수점 숫자가 평등을 위해 비교 될 수 없다는 일반적인 지혜는 부정확합니다. 부동 소수점 숫자는 정수와 다르지 않습니다. “a == b”로 평가하면 숫자가 같으면 true가되고 그렇지 않으면 false가됩니다 (두 개의 NaN은 물론 동일하지 않음).
실제 문제는 이것입니다 : 계산을했는데 비교 해야하는 두 숫자가 정확히 맞는지 확실하지 않으면 어떻게됩니까? 이 문제는 정수에서와 같이 부동 소수점에서 동일합니다. 정수 식 “7 / 3 * 3″을 평가하면 “7 * 3 / 3″과 같지 않습니다.
“정수와 정수를 어떻게 비교합니까?” 그런 상황에서. 단일 답변이 없습니다. 수행해야 할 작업은 특정 상황, 특히 어떤 종류의 오류 및 달성하려는 항목에 따라 다릅니다.
가능한 선택 사항은 다음과 같습니다.
수학적으로 정확한 숫자가 같으면 “진정한”결과를 얻으려면 수행하는 계산의 속성을 사용하여 두 숫자에서 동일한 오류가 발생 함을 증명할 수 있습니다. 이것이 가능하고 정확하게 계산 된 경우 동일한 숫자를 제공하는 표현식의 결과 인 두 숫자를 비교하면 비교에서 “참”이됩니다. 또 다른 방법은 계산의 속성을 분석하고 오류가 절대량 또는 입력 중 하나 또는 출력 중 하나에 상대적인 양을 절대 초과하지 않음을 증명할 수 있다는 것입니다. 이 경우 계산 된 두 숫자가 최대량만큼 다른지 물어보고 해당 간격 내에 있으면 “true”를 반환 할 수 있습니다. 에러 바운드를 증명할 수 없다면 당신은 추측하고 최선을 다하겠습니다. 추측하는 한 가지 방법은 많은 무작위 표본을 평가하고 결과에 어떤 종류의 분포가 있는지 확인하는 것입니다.
물론 수학적으로 정확한 결과가 같으면 “참”이라는 요구 사항 만 설정하기 때문에 결과가 같지 않아도 “참”이 될 가능성을 열어 두었습니다. (실제로 항상 “true”를 반환하여 요구 사항을 충족 할 수 있습니다. 이렇게하면 계산이 간단 해지지 만 일반적으로 바람직하지 않으므로 아래 상황 개선에 대해 논의하겠습니다.)
수학적으로 정확한 숫자가 다른 경우 “거짓”결과를 얻으려면 수학적으로 정확한 숫자가 다른 경우 숫자를 평가하면 다른 숫자가 생성됨을 증명해야합니다. 이것은 많은 일반적인 상황에서 실제적인 목적으로는 불가능할 수 있습니다. 대안을 생각해 봅시다.
수학적으로 정확한 숫자가 일정량 이상 차이가 나는 경우 “거짓”결과를 얻는 것이 유용한 요구 사항 일 수 있습니다. 예를 들어, 컴퓨터 게임에서 던진 공이 어디로 갔는지 계산할 것이며 공이 타격을 받았는지 알고 싶을 것입니다. 이 경우, 공이 방망이에 부딪히면 반드시 “참”을 원하고, 공이 방망이에서 멀어지면 “거짓”을하려고합니다. 수학적으로 정확한 시뮬레이션은 박쥐를 놓쳤지만 박쥐를 때리는 밀리미터 이내에 있습니다. 이 경우, 볼의 위치와 타석의 위치 계산시 최대 1 밀리미터 (모든 관심 위치에 대한)의 결합 오차가 있음을 증명 (또는 추측 / 추정)해야합니다. 이렇게하면 항상 “
따라서 부동 소수점 숫자를 비교할 때 반환 할 항목을 결정하는 방법은 특정 상황에 따라 크게 다릅니다.
계산에 대한 오류 범위를 증명하는 방법에 대해서는 복잡한 주제가 될 수 있습니다. 가장 가까운 반올림 모드에서 IEEE 754 표준을 사용하는 부동 소수점 구현은 기본 연산 (특히 곱셈, 나눗셈, 덧셈, 뺄셈, 제곱근)에 대한 정확한 결과에 가장 가까운 부동 소수점 숫자를 반환합니다. (동점의 경우, 라운드가 낮으므로 라운드 비트가 고르게됩니다.) (제곱근과 나눗셈에 특히주의하십시오. 언어 구현은 IEEE 754를 준수하지 않는 메소드를 사용할 수 있습니다.)이 요구 사항 때문에 단일 결과의 오류는 최하위 비트 값의 최대 1/2입니다. (더 많으면 반올림은 값의 1/2 내에있는 다른 숫자로 넘어 갔을 것입니다.)
거기에서 나아가는 것은 훨씬 더 복잡해진다. 다음 단계는 입력 중 하나에 이미 오류가있는 작업을 수행하는 것입니다. 간단한 표현식의 경우, 이러한 오류는 계산을 통해 최종 오류에 대한 경계에 도달 할 수 있습니다. 실제로 이것은 고품질 수학 라이브러리 작업과 같은 몇 가지 상황에서만 수행됩니다. 물론 어떤 작업이 수행되는지 정확하게 제어해야합니다. 고급 언어는 종종 컴파일러에게 많은 여유를 주므로 어떤 순서로 작업이 수행되는지 알 수 없습니다.
이 주제에 관해 쓰여질 수있는 것이 더 많지만 여기서 멈추어야합니다. 요약하면 답은 다음과 같습니다. 라이브러리 루틴에 넣을 가치가있는 대부분의 요구에 맞는 단일 솔루션이 없기 때문에이 비교에는 라이브러리 루틴이 없습니다. (상대 또는 절대 오류 간격과 비교하면 충분하므로 라이브러리 루틴없이 간단하게 수행 할 수 있습니다.)
답변
테스트 / TDD 컨텍스트에서 사용하려면 표준 방법이라고 말하고 싶습니다.
from nose.tools import assert_almost_equals
assert_almost_equals(x, y, places=7) #default is 7