Zoeken…


Zwevende puntnummers zijn raar

De eerste fout die bijna elke programmeur maakt, is ervan uitgaan dat deze code zal werken zoals bedoeld:

float total = 0;
for(float a = 0; a != 2; a += 0.01f) {
    total += a;
}

De beginnende programmeur gaat ervan uit dat dit elk getal in het bereik 0, 0.01, 0.02, 0.03, ..., 1.97, 1.98, 1.99 zal 0, 0.01, 0.02, 0.03, ..., 1.97, 1.98, 1.99 om het resultaat 199 - het wiskundig correcte antwoord.

Er gebeuren twee dingen die dit onwaar maken:

  1. Het geschreven programma eindigt nooit. a nooit gelijk aan 2 en de lus eindigt nooit.
  2. Als we de luslogica herschrijven om in plaats daarvan a < 2 te controleren, wordt de lus beëindigd, maar wordt het totaal iets anders dan 199 . Op IEEE754-compatibele machines zal het in plaats daarvan vaak oplopen tot ongeveer 201 .

De reden dat dit gebeurt is dat Floating Point Numbers benaderingen van hun toegewezen waarden vertegenwoordigen .

Het klassieke voorbeeld is de volgende berekening:

double a = 0.1;
double b = 0.2;
double c = 0.3;
if(a + b == c)
    //This never prints on IEEE754-compliant machines
    std::cout << "This Computer is Magic!" << std::endl; 
else
    std::cout << "This Computer is pretty normal, all things considered." << std::endl;

Hoewel de programmeur drie getallen ziet die zijn geschreven in base10, zien de compiler (en de onderliggende hardware) binaire getallen. Omdat 0.1 , 0.2 en 0.3 een perfecte deling door 10 vereisen - wat vrij eenvoudig is in een base-10-systeem, maar onmogelijk in een base-2-systeem - moeten deze nummers worden opgeslagen in onnauwkeurige formaten, vergelijkbaar met hoe het nummer 1/3 moet worden opgeslagen in de onnauwkeurige vorm 0.333333333333333... in base-10.

//64-bit floats have 53 digits of precision, including the whole-number-part.
double a =     0011111110111001100110011001100110011001100110011001100110011010; //imperfect representation of 0.1
double b =     0011111111001001100110011001100110011001100110011001100110011010; //imperfect representation of 0.2
double c =     0011111111010011001100110011001100110011001100110011001100110011; //imperfect representation of 0.3
double a + b = 0011111111010011001100110011001100110011001100110011001100110100; //Note that this is not quite equal to the "canonical" 0.3!


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow