0.1 float is groter dan 0.1 double. Ik verwachtte dat het onwaar zou zijn

Laat:

double d = 0.1;
float f = 0.1;

moet de uitdrukking

(f > d)

retourneer trueof false?

Empirisch gezien is het antwoord true. Ik verwachtte echter dat het falsezou zijn.

Omdat 0.1niet perfect kan worden weergegeven in binair getal, terwijl dubbel 15tot 16decimale cijfers heeft en float alleen 7. Ze zijn dus allebei minder dan 0.1, terwijl het dubbele dichter bij 0.1ligt.

Ik heb een exacte uitleg nodig voor de true.


Antwoord 1, autoriteit 100%

Ik zou zeggen dat het antwoord afhangt van de afrondingsmodus bij het converteren van de doublenaar float. floatheeft 24 binairebits precisie, en doubleheeft 53. In binair is 0.1:

0.1₁₀ = 0.0001100110011001100110011001100110011001100110011…₂
             ^        ^         ^   ^ 
             1       10        20  24

Dus als we naar bovenafronden op het 24e cijfer, krijgen we

0.1₁₀ ~ 0.000110011001100110011001101

wat groter is dan de exacte waarde en de nauwkeurigere benadering met 53 cijfers.


Antwoord 2, autoriteit 32%

Het getal 0.1 wordt met de gegeven precisie afgerond op de dichtstbijzijnde drijvende-kommaweergave. Deze benadering kan groter of kleiner zijn dan 0,1, dus zonder naar de werkelijke waarden te kijken, kunt u niet voorspellen of de benadering met enkele precisie of dubbele precisie groter is.

Hier wordt de waarde van de dubbele precisie afgerond (met behulp van een Python-interpreter):

>>> "%.55f" % 0.1
'0.1000000000000000055511151231257827021181583404541015625'

En hier is de enkele precisiewaarde:

>>> "%.55f" % numpy.float32("0.1")
'0.1000000014901161193847656250000000000000000000000000000'

Je kunt dus zien dat de benadering met enkele precisie groter is.


Antwoord 3, autoriteit 11%

Als u .1naar binair converteert, krijgt u:

0.000110011001100110011001100110011001100110011001100...

voor altijd herhalen

Toewijzing naar gegevenstypen, krijgt u:

float(.1) = %.00011001100110011001101
                   ^--- noot afronding
dubbel(.1) = %.0001100110011001100110011001100110011001100110011010

Converteer dat naar grondtal 10:

float(.1) = .10000002384185791015625
dubbel(.1) = .100000000000000088817841970012523233890533447265625

Dit is overgenomen uit een artikel geschreven door Bruce Dawson. het is hier te vinden:
Dubbels zijn geen floats, dus doe dat niet niet vergelijken


Antwoord 4, autoriteit 3%

Ik denk dat Eric Lipperts opmerkingop de vraag is eigenlijk de duidelijkste uitleg, dus ik zal het opnieuw posten als antwoord:

Stel dat u 1/9 berekent in 3-cijferige decimaal en 6-cijferig decimaal. 0,111 < 0.111111, toch?

Stel nu dat je 6/9 aan het berekenen bent. 0,667 > 0,6666667, toch?

Je kunt niet stellen dat 6/9 in driecijferige decimalen 0,666 is, want dat is niet de dichtstbijzijnde 3-cijferige decimaal tot 6/9!


Antwoord 5, autoriteit 2%

Omdat het niet exact kan worden weergegeven, is het vergelijken van 1/10 in basis 2 hetzelfde als het vergelijken van 1/7 in basis 10.

1/7 = 0,142857142857… maar als we op verschillende basis 10 precisies (3 versus 6 decimalen) vergelijken, hebben we 0,143 > 0.142857.


Antwoord 6

Om nog iets toe te voegen aan de andere antwoorden over IEEE-754 en x86: het probleem is nog ingewikkelder dan het lijkt. Er is niet “één” representatie van 0.1 in IEEE-754 – er zijn er twee. Ofwel afronding van het laatste cijfer naar beneden of naar boven zou geldig zijn. Dit verschil kan en komt ook voor, omdat x86 geen64-bits gebruikt voor zijn interne floating-point berekeningen; het gebruikt eigenlijk 80-bits! Dit wordt dubbele uitgebreide precisiegenoemd.

Dus, zelfs bij alleen x86-compilers, komt het soms voor dat hetzelfde getal op twee verschillende manieren wordt weergegeven, omdat sommige de binaire representatie berekenen met 64-bits, terwijl andere 80 gebruiken.


Het kan zelfs gebeuren met dezelfde compiler, zelfs op dezelfde machine!

#include <iostream>
#include <cmath>
void foo(double x, double y)
{
  if (std::cos(x) != std::cos(y)) {
    std::cout << "Huh?!?\n";  //← you might end up here when x == y!!
  }
}
int main()
{
  foo(1.0, 1.0);
  return 0;
}

Zie Waarom is cos(x) != cos(y)hoewel x == y?voor meer info.


Antwoord 7

De rang van double is hoger dan die van float in conversies. Door een logische vergelijking te maken, wordt f gecast om te verdubbelen en misschien geeft de implementatie die u gebruikt inconsistente resultaten. Als je f achtervoegt zodat de compiler het als een float registreert, dan krijg je 0.00 wat false is in dubbel type. Niet-toegevoegde drijvende typen zijn dubbel.

#include <stdio.h>
#include <float.h>
int main()
{
     double d = 0.1;
     float f = 0.1f;
     printf("%f\n", (f > d));
     return 0;
}

Other episodes