경험적으로, 대답은 더 없습니다. 입력 4503599761588224에 대한 결과는 67108864 대신 67108865로 잘못 계산됩니다.
다음 코드는이 사례를 식별합니다. 물론 break;
을 제거하여 다른 경우를 관찰 할 수 있습니다.
#include <stdio.h>
#include <stdint.h>
#include <math.h>
int main(void) {
for (uint32_t y = 1; y != 0; y++) {
// *Just* smaller than a perfect square
uint64_t x = ((uint64_t)y * (uint64_t)y) - 1;
// We expect the floor of the result
uint32_t expected = y - 1;
uint32_t result = (uint32_t)sqrt((double)x);
if (result != expected) {
printf("Incorrect: x = %llu, result = %u\n", x, result);
break;
}
}
return 0;
}
값 4503599761588224의 특별한 점은 무엇입니까? 음, 정확하게 (2 +1) -1, AKA (2)입니다. 정확하게 double
으로 표시 될 수 있으므로 long
->double
변환으로 인한 오류가 아닙니다.
대신 오류는 sqrt
구현 내부에 있습니다. 여기서 델타 (대 완벽한 사각형)는 제곱근을 약 2 -27으로 줄입니다.이 값은 2 번인 result
자체입니다. 이것은 배정도가 처리 할 수있는 한계에 달려 있으므로 당연히 오프 - 바이 - 원 오류를 볼 것으로 예상됩니다.
1. Live demo 2
. 당신이 당신의 수학 라이브러리의`sqrt` 좋은 및 C 알고있는 경우에도`uint32_t`에 대한 :)
아래 의견에 근본 원인을 식별하는 @EricPostpischil에
2. 신용, 이것은 단지 신뢰할 수있다 구현은 부동 소수점 연산에 적합합니다. C 표준만으로는 이것을 요구하지 않습니다. 일부 수학 라이브러리는 정확하게 제곱근을 표현할 수있는 값의 경우에도 근사 결과 만 반환합니다. –
나는 32 비트 정수의 이중 전략을 추천했지만 [Java answer]에 대한 응답으로 [대답] (https://stackoverflow.com/a/15212684/1798593)을 작성했습니다. 그 대답은 Java의 특정 보장에 달려 있으며 C에 적용되지 않습니다. –