2017-12-04 2 views
2

uint64_t의 정수 부분을 계산하고 싶습니다. 32 비트 uint32_t의 경우 먼저 double, sqrt으로 캐스팅 한 다음 uint32_t으로 다시 캐스팅하는 것이 좋습니다.double을 사용하는 정수 sqrt의 정확도

double은 정확히 2^53까지만 숫자를 수용 할 수 있다고 가정하면 uint64_t에서도 작동합니까? 즉, 항상 다음과 같은 올바른 대답을 줄 것입니다 : 심지어

#include <math.h> 
uint64_t x = ...; 
uint64_t result = (uint64_t)sqrt((double)x); 

또는 :

#include <math.h> 
uint64_t x = ...; 
uint32_t result = (uint32_t)sqrt((double)x); 
+0

아래 의견에 근본 원인을 식별하는 @EricPostpischil에

2. 신용, 이것은 단지 신뢰할 수있다 구현은 부동 소수점 연산에 적합합니다. C 표준만으로는 이것을 요구하지 않습니다. 일부 수학 라이브러리는 정확하게 제곱근을 표현할 수있는 값의 경우에도 근사 결과 만 반환합니다. –

+0

나는 32 비트 정수의 이중 전략을 추천했지만 [Java answer]에 대한 응답으로 [대답] (https://stackoverflow.com/a/15212684/1798593)을 작성했습니다. 그 대답은 Java의 특정 보장에 달려 있으며 C에 적용되지 않습니다. –

답변

4

경험적으로, 대답은 없습니다. 입력 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`에 대한 :)

+1

물론 수학 라이브러리가 적합하고 올바르게 반올림 된 제곱근을 반환한다고 가정하면 결과가 가깝고 쉽게 테스트 할 수 있으며 정수 산술로 정정하십시오. –

+2

2 \ * \ * 26에서 오류가 발생하는 이유는 sqrt (x)의 파생어가 1/(2 \ * sqrt (x))입니다. 따라서 (2 \ * \ * 26) ** 2에서 1을 뺀 것은 제곱근을 약 2 \ * \ * - 27 줄입니다. 그리고 제곱근은 2 * * \ * 26 바로 아래에 있으므로 제곱근은 제곱근의 약 2 배입니다. 따라서 방금 double precision의 가장자리에 도달했습니다. –

+0

수학 라이브러리가 매우 정확할지라도 제곱근을 괄호로 묶고 이진 검색을 수행 할 수 있습니다. –