2012-05-30 6 views
3

Я создаю приложение для вычисления чисел простых чисел в 64-битном диапазоне, поэтому, когда я попытался вычислить квадратный корень из 64-разрядного числа, используя sqrt функцию от math.h, я нашел ответ не точным например, когда вход ~0ull, ответ должен быть ~0u, но тот, который я получаю, является неправильным, поэтому я решил создать свою версию с использованием языка сборки x86, чтобы узнать, является ли это ошибкой, вот моя функция:это ошибка в sqrt-функции

inline unsigned prime_isqrt(unsigned long long value) 
{ 
    const unsigned one = 1; 
    const unsigned two = 2; 

    __asm 
    { 
     test dword ptr [value+4], 0x80000000 
     jz ZERO 
     mov eax, dword ptr [value] 
     mov ecx, dword ptr [value + 4] 

     shrd eax, ecx, 1 
     shr ecx, 1 
     mov dword ptr [value],eax 
     mov dword ptr [value+4],ecx 

     fild value 
     fimul two 
     fiadd one 
     jmp REST 
ZERO: 
     fild value 
REST: 
     fsqrt 
     fisttp value 
     mov eax, dword ptr [value] 
    } 
} 

ввод является нечетным числом, чтобы получить его квадратный корень. Когда я тестирую свою функцию с одним и тем же входом, результат был таким же.

То, что я не понимаю, - это то, почему эти функции охватывают результат или будут конкретными, почему sqrt инструкция по результату?

ответ

8

sqrt ничего не крутит - вы делаете, когда конвертируете целое число в двойное. Двойной не может представлять все числа, которые могут иметь 64-разрядное целое, без потери точности. В частности, начиная с 2 , существует несколько целых чисел, которые будут представлены как одно и то же двойное значение.

Так что, если вы преобразовать целое число выше 2 удвоить, вы потеряете некоторые из наименее значимых бит, поэтому (double)(~0ull) является +18446744073709552000,0, не 18446744073709551615,0 (или точнее последний фактически равен бывшим потому что они представляют одинаковое двойное число).

+0

спасибо, так что я могу взять младший 32-битный вычислить квадратный корень для него - называть его (а) - затем вычесть нижний 32-бит из 64-битного номера и получить квадратный корень для этого числа - назовите его (b) - теперь все Мне нужно сделать это умножить (а) на (б), и мы закончили. –

+1

@Muhammadalaa: Eh, no. 64 бита могут быть записаны математически как (H * 2^32 + L), где H и L - по 32 бита. Вы указываете, что 'sqrt (H * 2^32 + L)' = 'sqrt (L) * sqrt (H * 2^32)'. Это не так. Однако вы можете вычислить его как «sqrt (H) * sqrt (2^32 + L/H)». – MSalters

+0

Округление даст вам ошибку около 2^-53, но здесь ошибка составляет коэффициент 2: '~ 0u == UINT_MAX' против' 0x80000000 = UINT_MAX/2'. Я не думаю, что это объясняет это. – MSalters

0

Вы не очень четко знаете, какую функцию C++ вы вызываете. sqrt - перегруженное имя. Вероятно, вы хотели sqrt(double(~0ull)). Нет sqrt перегрузка, которая принимает unsigned long long.

+2

Он знает об этом. Он явно преобразует число в двойной код в свой код. – sepp2k

 Смежные вопросы

  • Нет связанных вопросов^_^