Laat:
double d = 0.1;
float f = 0.1;
moet de uitdrukking
(f > d)
retourneer true
of false
?
Empirisch gezien is het antwoord true
. Ik verwachtte echter dat het false
zou zijn.
Omdat 0.1
niet perfect kan worden weergegeven in binair getal, terwijl dubbel 15
tot 16
decimale cijfers heeft en float alleen 7
. Ze zijn dus allebei minder dan 0.1
, terwijl het dubbele dichter bij 0.1
ligt.
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 double
naar float
. float
heeft 24 binairebits precisie, en double
heeft 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 .1
naar 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;
}