2015-03-05 11 views
5

Obecnie piszę program, który musi wziąć podłogę z pierwiastkiem kwadratowym. Ponieważ wartość, którą biorę pierwiastek kwadratowy z jest dodatnia, po prostu rzucam ją do int. Tak mówią na poniższym przykładzie:C++ - Jak poprawnie obsłużyć podwójne do int

int i = 16; 
int j = std::sqrt(i) 

j powinny być 4.

Zastanawiam się jednak, czy to możliwe, że sqrt zwraca +3,9999999991 zamiast 4.000000001 lub cokolwiek, a wynikiem jest 3 j? Czy istnieją reguły definiujące zachowanie zmiennoprzecinkowe? Jak mogę właściwie przekonwertować to na int?

+9

int integer = std :: round (floating_point); –

+0

Nieco istotne, jeśli zależy Ci na zaokrągleniu: https://stackoverflow.com/questions/485525/round-for-float-in-c – tux3

+0

@ DieterLücking Myślę, że zaokrąglibyśmy do * najbliższego *, podczas gdy pożądanym rezultatem jest tutaj zaokrąglić w dół od tego, co byłoby "prawdziwym" pierwiastkiem kwadratowym. Na przykład. sqrt (16) -> 4, sqrt (15) -> 3 –

Odpowiedz

3

Prawie cały szeroko dostępny sprzęt korzysta z liczb zmiennoprzecinkowych IETF754, chociaż C++ tego nie wymaga.

Zakładając liczb zmiennoprzecinkowych IETF754 i bezpośrednie odwzorowanie ::std::sqrt do IETF754 zmiennoprzecinkowej operacji pierwiastkowania, masz pewność, co następuje:

  • 16 i 4 mogą zarówno być reprezentowane dokładnie w arytmetyce zmiennoprzecinkowej - w rzeczywistości, numery zmiennoprzecinkowych podwójnej precyzji może reprezentować dowolny 32 bitową liczbę całkowitą dokładnie
  • pierwiastek kwadratowy zwraca wynik, który jest najbliżej do bycia dokładny

Dlatego swój przykład will work fine.

Zasadniczo problem, o którym wspomniałeś, może się zdarzyć, ale aby go rozwiązać, musisz zadać większe pytanie: w jakich okolicznościach liczba jest zbliżona do integralnej, naprawdę integralna?

To jest rzeczywiście trudniejsze, niż mogłoby się wydawać, ponieważ chcesz obliczyć podłogę pierwiastka kwadratowego, a zatem po prostu zaokrąglanie nie będzie działać dla ciebie. Jednak, gdy już odpowiesz na to pytanie, wdrożenie rozwiązania powinno być raczej proste. Na przykład:

int i = 16; 
int j = std::sqrt(i); 
if((j + 1) * (j + 1) == i) j += 1;