Wczoraj zapytałem o question o to, dlaczego traciłem dokładność w arytmetyce zmiennoprzecinkowej. Otrzymałem odpowiedź na pytanie, jak to było z powodu wyników pośrednich przechowywanych w rejestrach x87. To było pomocne, ale niektóre szczegóły wciąż mi uciekają. Oto odmiana programu, który przedstawiłem w poprzednim pytaniu, używam VC++ 2010 Express w trybie debugowania.Dokładność zmiennoprzecinkowa ponownie
int main()
{
double x = 1.8939201459282359e-308; /* subnormal number */
double tiny = 4.9406564584124654e-324; /* smallest IEEE double */
double scale = 1.6;
double temp = scale*tiny;
printf("%23.16e\n", x + temp);
printf("%23.16e\n", x + scale*tiny);
}
Urządzenie wysyła
1.8939201459282369e-308
1.8939201459282364e-308
pierwsza wartość jest poprawna zgodnie ze standardem IEEE. Nadanie zmiennej scale
wartości 2.0 daje poprawną wartość dla obu obliczeń. Rozumiem, że temp
w pierwszym obliczeniu jest wartością podnormalną i dlatego traci precyzję. Rozumiem również, że wartość scale*tiny
jest przechowywana w rejestrze x87, który ma większy zakres wykładniczy, a więc ta wartość ma większą dokładność niż temp
. Czego nie rozumiem, gdy dodajemy wartość do x
, otrzymujemy poprawną odpowiedź z niższej dokładności. Z pewnością, jeśli niższa dokładność może dać poprawną odpowiedź, to wyższa dokładność powinna również dać poprawną odpowiedź? Czy ma to coś wspólnego z "podwójnym zaokrągleniem"?
Z góry dziękuję, to dla mnie zupełnie nowy temat, więc trochę się zmagam.
Następujące może być prawdą, ale nie jest to dla mnie oczywiste: * Oczywiście, jeśli niższa dokładność może dać poprawną odpowiedź, to wyższa dokładność powinna również dać poprawną odpowiedź? * – NPE
Gdybym był tobą , W takich obliczeniach użyłbym 'long double' ... –
Skąd wiemy, że niższa liczba precyzji nie ma losowej wartości w ostatniej cyfrze? Zawsze istnieje 10% szans na trafienie spodziewanego. –