2012-07-05 11 views
8
myInt = int(5 * myRandom()) 

myRandom() jest losowo wygenerowaną pływak, który powinny 0.2.Przesyłanie na błędy typu int i zmiennoprzecinkowe?

Należy zatem stwierdzić, że to oświadczenie ma być 1.

Moje pytanie: czy jest możliwe, że z powodu błędu zmiennoprzecinkowego NIE zostanie ocenione na 1?

Na przykład, jeżeli z powodu błędu zmiennoprzecinkowej czymś, co powinno być 0,2 to może być MNIEJ niż to? IE, na przykład pod uwagę następujące możliwości: 3

int(5 * 0.2)    = 1 //case 1 normal 
int(5 * 0.2000000000000001) = 1 //case 2 slightly larger, its OK 
int(5 * 0.1999999999999999) = 0 //case 3 negative, is NOT OK, as int() floors it 

Is case3 nawet możliwe ?, z 0.1999999999999999 być wynikiem błędu pływający punkt? Nigdy dotąd nie widziałem negatywnego epsilonu, tylko przypadek 2, kiedy jest nieco większy i to jest w porządku, jak wtedy, gdy jest rzutowany na int(), to "podłogi" do poprawnego wyniku. Jednak przy ujemnym efekcie epsilon efekt "podłogi" sprawi, że wynik 0.9999999999999996 będzie równy 0.

+0

Nie sądzę, że to możliwe, nie. Mnożenie i zaokrąglanie powinno uwzględniać tylko maksymalną liczbę możliwych cyfr znaczących. – Ryan

+1

Jeśli jest generowany losowo, dlaczego "powinien" być 0,2? –

+0

To jest C++, nie C. Nie można używać składni konstruktora w C. –

Odpowiedz

3

Nie można przywrócić myRandom .2 ponieważ .2 nie może być reprezentowany jako liczba zmiennoprzecinkowa ani podwójna, zakładając, że twój system docelowy używa binarnego standardu zmiennoprzecinkowego IEEE 754, który jest w przeważającej mierze domyślny.

Jeśli myRandom() zwróci reprezentowalną liczbę najbliższą .2, wówczas mojaInt będzie 1, ponieważ liczba najbliższa .2 reprezentowana jako liczba zmiennoprzecinkowa jest nieco większa niż .2 (to jest 0.20000000298023223876953125), a więc jest najbliższa reprezentowalna podwójne (0.20000000000000001110223024625156540423631668090820312).

W innych przypadkach nie będzie to prawda. Np najbliższy podwójna do .6 jest 0,59999999999999997779553950749686919152736663818359375, więc Myint będzie 2, a nie 3.

+0

Najbardziej lubię twoją odpowiedź, ale jest to niepokojące. Prawdziwy problem polegał na tym, że gdybym mógł uzyskać deterministyczny wynik, rzucając float na int, jednak z tego, co powiedziałeś o 0.6, nie wydaje się. Będę musiał wykonać niestandardowe zaokrąglenie. –

1

Tak, jest to możliwe, przynajmniej jeśli chodzi o standard C.

Wartość 0.2 nie może być dokładnie odwzorowana w binarnym formacie zmiennoprzecinkowym. Wartość zwrócona przez myRandom() będzie zatem albo nieco poniżej, albo nieco powyżej, wartości matematycznej 0.2. Standard C pozwala na uzyskanie dowolnego wyniku.

Teraz może być tak, że semantyka IEEE pozwala tylko na nieznacznie większy wynik niż 0.2 - ale standard C nie wymaga semantyki IEEE. A to zakłada, że ​​wynik jest wyprowadzony tak dokładnie jak to możliwe z wartości 0.2. Jeśli wartość jest generowana z szeregu operacji zmiennoprzecinkowych, z których każdy może wprowadzić niewielki błąd, może być z łatwością mniejsza lub większa niż 0.2.

+0

Jako dodatek, rzucając float do rundy w dół, więc jeśli wartość jest nieco większa niż 0,2, otrzymasz produkt o wartości nieco większej niż 1, który zaokrągli w dół. – Wug

+0

To tylko przykład, myRandom() może być dowolne od 0 do 1, ale 0.2 wydawało się dobrym przykładem, aby zilustrować różnicę między wynikami 0 i 1. Prawdziwy problem dotyczy determinizmu, szukałem w przypadku rzutowania Floatpoint na int, może to doprowadzić do deterministycznego wyniku. Wygląda na to, że nie. –

1

To nie jest zmiennoprzecinkowy błąd, tak działa zmiennoprzecinkowy punkt. Jakakolwiek część, która nie jest równa 1/(potęga 2), nie może być dokładnie odwzorowana i zostanie zaokrąglona do góry o lub o mniej niż do najbliższej reprezentowalnej liczby.

Możesz poprawić swój kod, mnożąc go przez małą wartość epsilon większą niż jeden przed konwersją na liczbę całkowitą.

myInt = int(5 * myRandom() * 1.000000000000001) 

Zobacz What Every Computer Scientist Should Know About Floating-Point Arithmetic.

0

Jest to możliwe, w zależności od liczby wybrać. Aby sprawdzić konkretny numer, zawsze możesz wydrukować je z dużą precyzją: printf ("% 1.50f", 0.2)

0

dlaczego nie pomnożyć liczby zmiennoprzecinkowej przez 5.0, a następnie użyć funkcji okrągłej, aby właściwie ją zaokrąglić?

+0

To jest ilustracja, nie są to rzeczywiste liczby. –

+0

Pomysł nadal działa. –

Powiązane problemy