Discussion:
C++ Maszynowe epsilon - dziwne wyniki
(Wiadomość utworzona zbyt dawno temu. Odpowiedź niemożliwa.)
wojtecc
2010-10-15 13:48:41 UTC
Permalink
Witam.
Wyznaczam w C++ maszynowe epsilon dla typu float:

/*======================*/
cout.precision(10);
float one = 1.0;
float a = 1.0;
float eps = 1.0;
float s;
float p = 1.0;

while((s = a + one) > one)
{
eps = p;
p = a /= 2.0;
}

cout << "Maszynowe epsilon: " << scientific << eps << endl;
/*======================*/

Dlaczego jak zmienię w kodzie:

/*======================*/
while((s = a + one) > one)
/*======================*/

na

/*======================*/
while((a + one) > one)
/*=================
R.M.M
2010-10-15 14:45:48 UTC
Permalink
Post by wojtecc
Witam.
/*======================*/
cout.precision(10);
float one = 1.0;
float a = 1.0;
float eps = 1.0;
float s;
float p = 1.0;
while((s = a + one)> one)
{
eps = p;
p = a /= 2.0;
}
cout<< "Maszynowe epsilon: "<< scientific<< eps<< endl;
/*======================*/
/*======================*/
while((s = a + one)> one)
/*======================*/
na
/*======================*/
while((a + one)> one)
/*======================*/
dostaję zły(inny) wynik?
Nie wiem na czym to kompilujesz, ale np. na http://ideone.com/ wynik
jest w obu przypadkach taki sam.
--
R.M.M
wojtecc
2010-10-15 15:51:08 UTC
Permalink
Post by wojtecc
Witam.
/*======================*/
cout.precision(10);
float one = 1.0;
float a = 1.0;
float eps = 1.0;
float s;
float p = 1.0;
while((s = a + one)>  one)
{
   eps = p;
   p = a /= 2.0;
}
cout<<  "Maszynowe epsilon: "<<  scientific<<  eps<<  endl;
/*======================*/
/*======================*/
while((s = a + one)>  one)
/*======================*/
na
/*======================*/
while((a + one)>  one)
/*======================*/
dostaję zły(inny) wynik?
Nie wiem na czym to kompilujesz, ale np. nahttp://ideone.com/wynik
jest w obu przypadkach taki sam.
--
R.M.M
Właśnie zauważyłem, że zależy to od kompilatora. Korzystam z g++ w
wersji 4.5.1. Jeśli kompiluję bez optymalizacji to dostaję zły wynik w
drugim przypadku. Natomiast jeśli kompiluję z optymalizacją (-O2) to
wyniki w obu przypadkach są takie same. Pytanie tylko dlaczego
kompilator g++ daje złe wyniki jeśli nie kompiluje się z optymalizacją?
Michoo
2010-10-15 16:17:49 UTC
Permalink
Post by wojtecc
Właśnie zauważyłem, że zależy to od kompilatora. Korzystam z g++ w
wersji 4.5.1. Jeśli kompiluję bez optymalizacji to dostaję zły wynik w
drugim przypadku. Natomiast jeśli kompiluję z optymalizacją (-O2) to
wyniki w obu przypadkach są takie same. Pytanie tylko dlaczego
kompilator g++ daje złe wyniki jeśli nie kompiluje się z optymalizacją?
Nie patrzyłem do disassembli, ale strzelam, że dlatego, że precyzja typu
"float" jest sporo poniżej precyzji maszynowej, więc dopóki nie jest
robiony zapis zawartości rejestru do pamięci obliczenia są na szerszym
typie.
--
Pozdrawiam
Michoo
Tomasz Sowa
2010-10-15 21:54:29 UTC
Permalink
Post by wojtecc
Właśnie zauważyłem, że zależy to od kompilatora. Korzystam z g++ w
wersji 4.5.1. Jeśli kompiluję bez optymalizacji to dostaję zły wynik w
drugim przypadku.
[...]

Jeśli pod pojęciem epsilon chcesz najmniejszą możliwą wartość którą można
zapisać w typie float to można to zrobić tak:

#include<iostream>
#include<stdint.h>

int main()
{
union
{
float f;
uint32_t i;
} u;

u.i = 1;
std::cout << "Maszynowe epsilon: " << u.f << std::endl;
}

czyli exponent jest ustawiony na zero, mantyssa (F) ustawiona na 1 i
wartość jaką ma obiekt to (jest to postać nie-znormalizowana):
V=(-1)**S * 2 ** (-126) * (0.F)

czyli:
Maszynowe epsilon: 1.4013e-045
--
Tomek
http://www.ttmath.org
Marcin 'Qrczak' Kowalczyk
2010-10-16 06:15:36 UTC
Permalink
Post by Tomasz Sowa
Jeśli pod pojęciem epsilon chcesz najmniejszą możliwą wartość którą można
zapisać w typie float
Nie. Epsilonem w tym kontekście nazywa się różnicę między następną
liczbą po 1 a 1.
Tomasz Sowa
2010-10-16 11:00:43 UTC
Permalink
Dnia Fri, 15 Oct 2010 23:15:36 -0700 (PDT), Marcin 'Qrczak' Kowalczyk
Post by Marcin 'Qrczak' Kowalczyk
Nie. Epsilonem w tym kontekście nazywa się różnicę między następną
liczbą po 1 a 1.
a to inna bajka, można tak:

#include <iostream>
#include <stdint.h>

int main()
{
union
{
float f;
uint32_t i;
} u1, u2, u3;

u1.i = 0x3F800000; // jeden
u2.i = 0x3F800001; // jeden i ciupka
u3.f = u2.f - u1.f;

std::cout << "Maszynowe epsilon: " << u3.f << std::endl;
}
--
Tomek
http://www.ttmath.org
Piotr Wyderski
2010-10-18 13:35:35 UTC
Permalink
Post by wojtecc
Właśnie zauważyłem, że zależy to od kompilatora. Korzystam z g++ w
wersji 4.5.1. Jeśli kompiluję bez optymalizacji to dostaję zły wynik w
drugim przypadku. Natomiast jeśli kompiluję z optymalizacją (-O2) to
wyniki w obu przypadkach są takie same. Pytanie tylko dlaczego
kompilator g++ daje złe wyniki jeśli nie kompiluje się z optymalizacją?
Część zmiennoprzecinkowa zbioru instrukcji operuje na rejestrach
mających większą precyzję, niż to wynika ze specyfikacji danego
typu zmiennoprzecinkowego. Odpowiednie zawężenie (zaokrąglenie,
obcięcie itd.) jest wykonywane dopiero podczas operacji zapisu
do pamięci (fst/fstp), dlatego wynik zależy od tego, czy i jak
często wartości pośrednie podróżowały między pamięcia a zbiorem rejestrów.

Są ludzie, którzy uzyskiwanie innych wyników takiego programu
w zależności od ustawień kompilatora potrafią nazwać słowem
"optymalizacja" i mimo tego później móc spojrzeć w lustro, lecz
nie wszyscy podzielają ich elastyczność terminologiczną.

Jeśli chcesz mieć nieco bardziej przewidywalne programy, użyj
opcji -ffloat-store, albo -- znacznie lepiej! -- przejdź na
SSE za pomocą opcji -mfpmath=sse2.

Pozdrawiam
Piotr Wyderski

wojtecc
2010-10-15 15:57:30 UTC
Permalink
Post by wojtecc
Witam.
/*======================*/
cout.precision(10);
float one = 1.0;
float a = 1.0;
float eps = 1.0;
float s;
float p = 1.0;
while((s = a + one)>  one)
{
   eps = p;
   p = a /= 2.0;
}
cout<<  "Maszynowe epsilon: "<<  scientific<<  eps<<  endl;
/*======================*/
/*======================*/
while((s = a + one)>  one)
/*======================*/
na
/*======================*/
while((a + one)>  one)
/*======================*/
dostaję zły(inny) wynik?
Nie wiem na czym to kompilujesz, ale np. nahttp://ideone.com/wynik
jest w obu przypadkach taki sam.
--
R.M.M
Sorry za PW - dawno nie obsługiwałem klienta usenetu oraz śpieszyłem
się i pomyłkowo wysłałem na PW wiadomość.
Loading...