GHCI는 왜 1.1 + 1.1 + 1.1> 3.3이 사실이라고 말합니까?
-
19-09-2019 - |
문제
나는 최근에 Haskell 튜토리얼을 겪고 있었고 대화식에서 간단한 Haskell 표현을 시도 할 때이 행동을 발견했습니다. ghci
껍데기:
Prelude> 1.1 + 1.1 == 2.2
True
Prelude> 1.1 + 1.1 + 1.1 == 3.3
False
Prelude> 1.1 + 1.1 + 1.1 > 3.3
True
Prelude> 1.1 + 1.1 + 1.1
3.3000000000000003
그 이유를 아는 사람이 있습니까?
해결책
왜냐하면 1.1
그리고 3.3
~이다 부동 소수점 번호. .1 또는 .3과 같은 10 진수 분획은 이진 부동물 지점 수에서 정확하게 표현할 수 없습니다. .1은 1/10을 의미합니다. 이진에서이를 나타내려면, 각 분수 숫자는 1/2를 나타냅니다.N (1/2, 1/4, 1/8 등), 무한히 반복되는 무한 수의 숫자가 필요합니다.
이것은베이스 10에서 1/3을 나타내는 것과 정확히 같은 문제입니다.베이스 10에서는 1/3을 정확하게 나타내려면 영원히 .33333 ... 영원히 무한 수의 숫자가 필요합니다. 따라서베이스 10에서 일하는 것은 보통 .33과 같은 것입니다. 그러나 그 사본 3 부를 추가하면 1이 아닌 .99를 얻습니다.
주제에 대한 자세한 내용은 읽으십시오 모든 컴퓨터 과학자가 부동 소수점 산술에 대해 알아야 할 것.
Haskell에서 합리적 숫자를보다 정확하게 표현하려면 항상 합리적인 데이터 유형을 사용할 수 있습니다. Ratio
; Bignums와 결합 (임의로 큰 정수, Integer
Haskell에서는 반대로 Int
분자 및 분모의 유형으로 고정 된 크기입니다)는 임의로 정확한 합리적 숫자를 나타낼 수 있지만 하드웨어로 구현되고 속도에 최적화 된 부동 소수점 수보다 속도가 상당히 느려집니다.
플로팅 포인트 숫자는 과학적 및 수치 계산을 위해 최적화로 고속으로 정밀도를 트레이드하여 반올림을 알고있는 한 소량의 컴퓨터를 수행 할 수 있으며 계산에 미치는 영향 .
다른 팁
부동 소수점 숫자는 정확하지 않기 때문입니다(위키 백과)
합리적인 유형을 사용하여 Haskell의 부동 소수점 오류를 피할 수 있습니다.
Prelude Data.Ratio> let a = (11 % 10) + (11 % 10) + (11 % 10)
Prelude Data.Ratio> a > (33 % 10)
False
Prelude Data.Ratio> fromRational a
3.3
물론, 당신은 정확도 증가에 대한 성능 페널티를 지불합니다.
일반적인 부동 소수점 오류 문제처럼 보입니다.
IEEE 부동 소수점 번호가 작동하는 방식과 관련이 있습니다.
1.1은 플로팅 포인트에서 1.1000000000000001로 표시되며 3.3은 3.2999999999999998로 표시됩니다.
따라서 1.1 + 1.1 + 1.1은 실제로입니다
1.1000000000000001 + 1.1000000000000001 + 1.1000000000000001 = 3.3000000000000003
보시다시피 실제로는 실제로 3.2999999999999998보다 큽니다.
일반적인 해결 방법은 평등을 평가하지 않거나 숫자가 대상 내에 있는지 확인하는 것입니다.
예 : 둘 다 참이면 합계는 3.3 (허용 오류 내)과 "동일"합니다.
1.1 + 1.1 + 1.1 < 3.3 + 1e9
1.1 + 1.1 + 1.1 > 3.3 - 1e9
IEEE 754 표현을 사용하여 정확히 수레를 표현할 수있는 수레는 거의 없으므로 항상 약간 떨어질 것입니다.
일반적으로 평등을 위해 부유물을 비교해서는 안됩니다 (위에 설명 된 이유로). 내가 생각할 수있는 유일한 이유는 당신이 "이 가치가 바뀌 었습니까?"라고 말하고 싶은 경우입니다. 예를 들어, "if (NewsCore /= OldScore)"그런 다음 조치를 취하십시오. 두 개의 별도 계산 결과를 비교하여 동일인지 확인하기 위해 두 개의 별도 계산 결과를 비교하지 않는 한 괜찮습니다 (수학적으로도 수학적으로도 다른 둥글 수도 있기 때문입니다).