2012-03-14 16 views
56

Powiel możliwe:
round() for float in C++C++: Jak zaokrąglić double do int?

mam podwójne (nazwijmy go X), miało być 55, ale w rzeczywistości przechowywane jako 54.999999999999943157 który właśnie realizowany.

Więc kiedy zrobić

double x = 54.999999999999943157; 
int y = (int) x; 

y = 54 zamiast 55!

To zdziwiło mnie przez długi czas. Jak mogę go poprawnie zaokrąglić?

+1

Można dodać 0,5 do liczby, a następnie wykonać rzutowanie, aby umożliwić obcięcie do int. Czy musisz zaokrąglić liczby ujemne? – Blastfurnace

+1

Możesz użyć tej definicji preprocesora: '#define ROUND_2_INT (f) ((int) (f> = 0.0? (F + 0.5): (f - 0.5)))' – c00000fd

+0

W rzeczywistości 54,999999999999943157 to 8 ULP poniżej _exactly representable_ 55 if przez "podwójne" masz na myśli binary64 z IEEE 754. Więc to nie jest sposób, w jaki 55 jest przechowywany, jest konsekwencją tego, jak nieprecyzyjne były twoje obliczenia. – Ruslan

Odpowiedz

85

dodać 0,5 przed odlewaniem (jeśli x> 0) lub odejmowanie 0,5 (jeśli X < 0), ponieważ kompilator zawsze obciąć.

float x = 55; // stored as 54.999999... 
x = x + 0.5; // x is now 55.499999... 
int y = (int)x; // truncated to 55 

C++ 11 wprowadza również std::round, która prawdopodobnie wykorzystuje podobną logikę dodanie 0,5 | x | pod maską (patrz link, jeśli zainteresowany), ale jest oczywiście bardziej solidny.

Kolejnym pytaniem może być dlaczego pływak nie jest przechowywany jako dokładnie 55. Aby uzyskać wyjaśnienie, zobacz odpowiedź this stackoverflow.

+0

Dziękuję ... to jest tak proste, w rzeczywistości – midnightBlue

+0

będzie działać równie dobrze z tylko int y = x + 0,5; choć prawda? – midnightBlue

+0

Tak, tak myślę. – Moritz

31

Rzucanie nie jest operacją matematyczną i nie zachowuje się w ten sposób. Próby

int y = (int)round(x); 
+7

Gips jest niepotrzebny; wynik zostanie niejawnie przekonwertowany na 'int'. –

+5

Nie mogłem sobie przypomnieć reguł promocji promocji typu C i myślę, że nie zaszkodzi to wszędzie, gdy chodzi o typowe rzuty, które są tak kleistym problemem. –

+0

Która biblioteka jest częścią "okrągłego"? AFAIK, którego nie ma w standardowej bibliotece C++. Dostępne są 'ceil' i' floor'. –

4

Odlewanie do int powoduje obcięcie wartości. Dodanie 0.5 powoduje, że wykonuje właściwe zaokrąglenie.

int y = (int)(x + 0.5); 
+3

nie dotyczy liczb ujemnych, jak wspomniano w jednym z powyższych komentarzy. Jeśli to robisz, możesz użyć "podłogi" zamiast rzutowania. –

3

Warto zauważyć, że to, co robisz, nie zaokrągla, to jest rzucanie. Przesyłanie przy użyciu (int) x powoduje obcięcie wartości dziesiętnej x. Jak w twoim przykładzie, jeśli x = 3.9995, .9995 zostanie obcięte i x = 3.

Zgodnie z propozycją wielu innych, jednym z rozwiązań jest dodanie 0.5 do x, a następnie rzutowanie.

+0

Dziękuję, tak naprawdę tylko zdałem sobie sprawę, że muszę nawet zaokrąglić (używam tylko liczb całkowitych w moim programie) – midnightBlue

-4
#include <iostream> 
#include <cmath> 
using namespace std; 

int main() 
{ 
    double x=54.999999999999943157; 
    int y=ceil(x);//The ceil() function returns the smallest integer no less than x 
    return 0; 
} 
+5

Wymusza to zwiększenie liczby ... 54.000000000000001 stanie się 55. –

+1

@AlbertRenshaw, right - co oznacza, że ​​ta odpowiedź jest błędna . –