Niedawno czytałem post: Double or Nothing from GOTW by Herb Sutter jestem trochę mylić z wyjaśnieniem następującego programu:Zrozumienie Guru tygodnia # 67: Double or Nothing
int main()
{
double x = 1e8;
while(x > 0)
{
--x;
}
}
Załóżmy, że ten kod jest uruchamiany 1 sekunda w jakiejś maszynie. Zgadzam się z tym, że kod taki jak ten jest głupi.
Jednak za wyjaśnienie problemu, jeśli zmienimy x
z float
na double
, to w niektórych kompilatorach będzie utrzymywać komputer w nieskończoności. Wyjaśnienie opiera się na następującym cytacie ze standardu.
Cytowanie z sekcji 3.9.1/8 z normą ++ C:
Istnieją trzy typy zmiennym punkcie: pływak, dwu- i długości dwukrotnie. Typ double zapewnia co najmniej taką samą precyzję, jak float, a double double typu zapewnia co najmniej taką samą precyzję, jak double. Zbiór wartości typu float jest podzbiorem zestawu wartości typu double; zestaw wartości typu double jest podzbiorem zestawu wartości typu double double.
Pytanie o kod to:
Jak długo można się spodziewać, że do podjęcia, jeśli zmienisz "double" do "float"? Czemu?
Oto wyjaśnienie podane:
to prawdopodobnie będzie albo około 1 sekundę (na konkretnym pływaków realizacja może być nieco szybciej, tak szybko, lub nieco wolniej niż w deblu), albo na zawsze , w zależności od tego, czy float może dokładnie reprezentować wszystkie wartości całkowite od 0 do 1e8 włącznie.
Powyższy cytat ze standardu oznacza, że mogą istnieć wartości, które mogą być reprezentowane przez podwójne, ale które nie mogą być reprezentowane przez zmienną. W szczególności, na niektórych popularnych platformach i kompilatorach, double może dokładnie reprezentować wszystkie wartości całkowite w [0,1e8], ale float nie może.
Co jeśli float nie może dokładnie reprezentować wszystkich wartości całkowitych od 0 do 1e8? Następnie zmodyfikowany program rozpocznie odliczanie, ale ostatecznie osiągnie wartość N, która nie może być reprezentowana i dla której N-1 == N (z powodu niewystarczającej precyzji zmiennoprzecinkowej) ... i
Moje pytanie brzmi:
Jeśli float nie jest nawet w stanie reprezentować 1e8
, to powinniśmy mieć przepełnienie już po zainicjowaniu float x = 1e8
; jak to możliwe, że komputer będzie działał wiecznie?
Próbowałem prosty przykład tutaj (choć nie double
ale int
)
#include <iostream>
int main()
{
int a = 4444444444444444444;
std::cout << "a " << a << std::endl;
return 0;
}
It outputs: a -1357789412
Oznacza to, że jeśli kompilator nie jest w stanie reprezentować daną liczbę z int
typu, spowoduje to przepełnienie.
Czy źle odczytałem? Jaki punkt, który przeoczyłem? Czy zmiana nieokreślonego zachowania x
z double
na float
?
Dziękujemy!
dziękuję za miłą informację, ale moje pytanie brzmi, dlaczego pętla while zacznie się nawet, jeśli mamy przepełnienie podczas inicjalizacji? – taocp
@taocp Nie masz przepełnienia podczas inicjalizacji. Formaty zmiennoprzecinkowe mają stale niższą * dokładność *, gdy przechodzisz do wyższych wartości, aż osiągniesz + 1. # INF. Operacje w nieskończoności, & # NAN są legalne, a nie nieokreślone. Mogą jednak mieć nieoczekiwane rezultaty. Spójrz na standard [IEEE-754] (https://en.wikipedia.org/wiki/IEEE_floating_point) –
@ ndeterminerminately sequenced ah, wielkie dzięki za to. – taocp