Sök…


Flyttalsnummer är konstiga

Det första misstaget som nästan varje programmerare gör är att förutsätta att den här koden fungerar som avsedd:

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

Nybörjare programmerar antar att detta kommer att sammanfatta varje enskilt nummer i intervallet 0, 0.01, 0.02, 0.03, ..., 1.97, 1.98, 1.99 , för att ge resultatet 199 - det matematiskt korrekta svaret.

Två saker händer som gör detta osant:

  1. Programmet som skrivet avslutas aldrig. a blir aldrig lika med 2 , och slingan upphör aldrig.
  2. Om vi skriver om slinglogiken för att kontrollera a < 2 istället upphör slingan, men det totala slutet blir något annorlunda än 199 . På IEEE754-kompatibla maskiner kommer det ofta att uppgå till cirka 201 istället.

Anledningen till att detta händer är att flytande punktnummer representerar ungefärliga värden .

Det klassiska exemplet är följande beräkning:

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;

Men vad vi programmeraren ser är tre siffror skrivna i base10, men kompilatorn (och den underliggande hårdvaran) ser är binära siffror. Eftersom 0.1 , 0.2 och 0.3 kräver perfekt uppdelning med 10 - vilket är ganska enkelt i ett bas-10-system, men omöjligt i ett bas-2-system - måste dessa nummer lagras i exakta format, liknande hur numret 1/3 måste lagras i den ofullständiga formen 0.333333333333333... i 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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow