Ik heb gelezen over het verschil tussen dubbele precisie en enkele precisie. In de meeste gevallen lijkt float
en double
Wisselbaar te zijn, d.w.z. het gebruik van een of de ander niet lijkt te beïnvloeden van de resultaten. Is dit echt het geval? Wanneer zijn drijvers en verdubbeling verwisselbaar? Wat zijn de verschillen tussen hen?
Antwoord 1, Autoriteit 100%
Enorm verschil.
Zoals de naam impliceert, een double
heeft 2x De precisie van float
[1] sup>. In het algemeen een double
heeft 15 decimale cijfers van precisie, terwijl float
heeft 7.
Hier is hoe het aantal cijfers wordt berekend:
double
heeft 52 mantissa bits + 1 verborgen bit: log (2 53 sup>) ÷ log (10) = 15.95 cijfers
float
heeft 23 mantissa bits + 1 verborgen bit: log (2 24 sup>) ÷ Log (10) = 7,22 cijfers
Dit precisieverlies kan leiden tot grotere truncatiefouten die worden geaccumuleerd wanneer herhaalde berekeningen worden uitgevoerd, b.v.
float a = 1.f / 81;
float b = 0;
for (int i = 0; i < 729; ++ i)
b += a;
printf("%.7g\n", b); // prints 9.000023
terwijl
double a = 1.0 / 81;
double b = 0;
for (int i = 0; i < 729; ++ i)
b += a;
printf("%.15g\n", b); // prints 8.99999999999996
Ook is de maximale waarde van float ongeveer 3e38
, maar dubbel gaat over 1.7e308
, dus met float
kan “Infinity” raken (dwz een speciaal drijvend nummer) veel gemakkelijker dan double
voor iets eenvoudigs, bijv het berekenen van het factoriaal van 60.
Tijdens het testen bevatten misschien een paar testcases deze enorme cijfers, waardoor uw programma’s mislukt als u drijvers gebruikt.
Natuurlijk, soms, zelfs double
is niet nauwkeurig genoeg, vandaar hebben we soms long double
[1] sup>(het bovenstaande voorbeeld Geeft 9.000000000000000066 op Mac), maar alle drijvende puntentypen lijden aan afrondingsfouten , dus als precisie erg belangrijk is (bijv. Geldverwerking), moet u int
of een fractie gebruiken klasse.
Gebruik bovendien niet +=
om veel zwevende puntnummers samen te stellen, aangezien de fouten snel accumuleren. Als u Python gebruikt, gebruikt u fsum
. Anders probeer het Kahan SumPation Algorithm te verkennen.
[1]: De C- en C++ -normen Geef de weergave van float
, double
en long double
. Het is mogelijk dat alle drie worden geïmplementeerd als IEEE Double-Precision. Desalniettemin, voor de meeste architecturen (GCC, MSVC; X86, X64, ARM) float
is inderdaad een IEEE-precisie drijvend puntnummer (Binary32) en double
is een IEEE dubbel-precisie drijvend puntnummer (Binary64). sup>
Antwoord 2, Autoriteit 10%
Hier is wat de standaard C95 (ISO-IEC 9899 6.2.5 §10) of C++ 2003 (ISO-IEC 14882-2003 3.1.9 §8) Normen zeggen:
Er zijn drie typen drijvende komma:
float
,double
enlong double
. Het typedouble
geeft minstens zoveel precisie alsfloat
, en het typelong double
geeft minstens zoveel precisie alsdouble
. De set waarden van het typefloat
is een subset van de set waarden van het typedouble
; de set waarden van het typedouble
is een subset van de set waarden van het typelong double
.
De C++-standaard voegt toe:
De waarderepresentatie van typen met drijvende komma is door de implementatie gedefinieerd.
Ik raad je aan om de uitstekende What Every Computerwetenschappers moeten weten over drijvende-komma-rekenkundedie de IEEE-standaard voor drijvende komma diepgaand behandelt. Je leert over de weergavedetails en je zult je realiseren dat er een afweging is tussen grootte en precisie. De precisie van de drijvende-kommaweergave neemt toe naarmate de grootte afneemt, dus drijvende-kommagetallen tussen -1 en 1 zijn die met de meeste precisie.
Antwoord 3, autoriteit 5%
Gegeven een kwadratische vergelijking: x2 − 4000000 x + 3.9999999 = ;0, de exacte wortels tot 10 significante cijfers zijn, r1 = 2.000316228 en r2 = 1.999683772.
Met float
en double
kunnen we een testprogramma schrijven:
#include <stdio.h>
#include <math.h>
void dbl_solve(double a, double b, double c)
{
double d = b*b - 4.0*a*c;
double sd = sqrt(d);
double r1 = (-b + sd) / (2.0*a);
double r2 = (-b - sd) / (2.0*a);
printf("%.5f\t%.5f\n", r1, r2);
}
void flt_solve(float a, float b, float c)
{
float d = b*b - 4.0f*a*c;
float sd = sqrtf(d);
float r1 = (-b + sd) / (2.0f*a);
float r2 = (-b - sd) / (2.0f*a);
printf("%.5f\t%.5f\n", r1, r2);
}
int main(void)
{
float fa = 1.0f;
float fb = -4.0000000f;
float fc = 3.9999999f;
double da = 1.0;
double db = -4.0000000;
double dc = 3.9999999;
flt_solve(fa, fb, fc);
dbl_solve(da, db, dc);
return 0;
}
Het uitvoeren van het programma geeft me:
2.00000 2.00000
2.00032 1.99968
Merk op dat de aantallen niet groot zijn, maar toch krijg je annuleringseffecten met float
.
(In feite is het bovenstaande niet de beste manier om kwadratische vergelijkingen op te lossen met behulp van drijvende-kommagetallen met enkele of dubbele precisie, maar het antwoord blijft ongewijzigd, zelfs als men een stabielere methode.)
Antwoord 4, autoriteit 3%
- Een dubbele is 64 en enkele precisie
(float) is 32 bits. - De dubbele heeft een grotere mantisse (de gehele bits van het reële getal).
- Onnauwkeurigheden worden kleiner in het dubbele.
Antwoord 5, autoriteit 2%
De grootte van de getallen die betrokken zijn bij de float-point berekeningen is niet het meest relevante. Het is de berekening die wordt uitgevoerd die relevant is.
In essentie, als u een berekening uitvoert en het resultaat is een irrationeel getal of een recurrente decimaal, dan zijn er afrondingsfouten wanneer dat aantal wordt ingepakt in de finite-grootte-gegevensstructuur die u gebruikt. Omdat Double tweemaal zo groot is van float, is de afrondingsfout een stuk kleiner.
De tests kunnen specifiek nummers gebruiken die dit soort fout veroorzaken en daarom wordt getest dat u het juiste type in uw code hebt gebruikt.
Antwoord 6, Autoriteit 2%
Ik heb net een fout opgetreden die me voor altijd kostte om erachter te komen en kan je potentieel een goed voorbeeld geven van floatprecisie.
#include <iostream>
#include <iomanip>
int main(){
for(float t=0;t<1;t+=0.01){
std::cout << std::fixed << std::setprecision(6) << t << std::endl;
}
}
De uitvoer is
0.000000
0.010000
0.020000
0.030000
0.040000
0.050000
0.060000
0.070000
0.080000
0.090000
0.100000
0.110000
0.120000
0.130000
0.140000
0.150000
0.160000
0.170000
0.180000
0.190000
0.200000
0.210000
0.220000
0.230000
0.240000
0.250000
0.260000
0.270000
0.280000
0.290000
0.300000
0.310000
0.320000
0.330000
0.340000
0.350000
0.360000
0.370000
0.380000
0.390000
0.400000
0.410000
0.420000
0.430000
0.440000
0.450000
0.460000
0.470000
0.480000
0.490000
0.500000
0.510000
0.520000
0.530000
0.540000
0.550000
0.560000
0.570000
0.580000
0.590000
0.600000
0.610000
0.620000
0.630000
0.640000
0.650000
0.660000
0.670000
0.680000
0.690000
0.700000
0.710000
0.720000
0.730000
0.740000
0.750000
0.760000
0.770000
0.780000
0.790000
0.800000
0.810000
0.820000
0.830000
0.839999
0.849999
0.859999
0.869999
0.879999
0.889999
0.899999
0.909999
0.919999
0.929999
0.939999
0.949999
0.959999
0.969999
0.979999
0.989999
0.999999
Zoals je kunt zien na 0,83, neemt de precisie aanzienlijk af.
Als ik t
echter als dubbel instel, zal een dergelijk probleem zich niet voordoen.
Het kostte me vijf uur om deze kleine fout te realiseren, die mijn programma verpestte.
Antwoord 7, autoriteit 2%
Type float, 32 bits lang, heeft een nauwkeurigheid van 7 cijfers. Hoewel het waarden kan opslaan met een zeer groot of zeer klein bereik (+/- 3,4 * 10^38 of * 10^-38), heeft het slechts 7 significante cijfers.
Typ dubbel, 64 bits lang, heeft een groter bereik (*10^+/-308) en 15-cijferige precisie.
Type long double is nominaal 80 bits, hoewel een bepaalde compiler/OS-koppeling het kan opslaan als 12-16 bytes voor uitlijningsdoeleinden. De lange dubbel heeft een exponent die gewoon belachelijk groot is en een precisie van 19 cijfers zou moeten hebben. Microsoft beperkt in hun oneindige wijsheid long double tot 8 bytes, hetzelfde als gewoon double.
Gebruik in het algemeen gewoon type double als je een drijvende-kommawaarde/variabele nodig hebt. Letterlijke drijvende-kommawaarden die in uitdrukkingen worden gebruikt, worden standaard als dubbel behandeld, en de meeste wiskundige functies die drijvende-kommawaarden retourneren, worden verdubbeld. Je bespaart jezelf veel kopzorgen en typecasting als je gewoon dubbel gebruikt.
Antwoord 8, autoriteit 2%
Floats hebben minder precisie dan doubles. Hoewel je het al weet, lees je Wat we moeten weten over drijvende-komma-rekenkundevoor een beter begrip.
Antwoord 9
Er zijn drie typen drijvende komma:
- zweven
- dubbel
- lang dubbel
Een eenvoudig Venn-diagram geeft uitleg over:
De reeks waarden van de typen
Antwoord 10
Als u drijvende-kommagetallen gebruikt, kunt u er niet op vertrouwen dat uw lokale tests exact hetzelfde zijn als de tests die aan de serverzijde worden uitgevoerd. De omgeving en de compiler zijn waarschijnlijk anders op uw lokale systeem en waar de laatste tests worden uitgevoerd. Ik heb dit probleem al vaker gezien in sommige TopCoder-competities, vooral als je twee getallen met drijvende komma probeert te vergelijken.
Antwoord 11
De ingebouwde vergelijkingsbewerkingen verschillen, zoals wanneer u 2 getallen met een drijvende komma vergelijkt, het verschil in gegevenstype (d.w.z. zwevend of dubbel) kan resulteren in verschillende resultaten.
Antwoord 12
Als men met embedded processing werkt, zal uiteindelijk de onderliggende hardware (bijv. FPGA of een specifiek processor-/microcontrollermodel) float optimaal in hardware geïmplementeerd hebben, terwijl double softwareroutines zal gebruiken. Dus als de precisie van een float voldoende is om aan de behoeften te voldoen, zal het programma enkele keren sneller worden uitgevoerd met float dan met dubbel. Zoals vermeld bij andere antwoorden, pas op voor accumulatiefouten.
Antwoord 13
In tegenstelling tot een int
(geheel getal), heeft een float
een decimale punt, net als een double
.
Maar het verschil tussen de twee is dat een double
twee keer zo gedetailleerd is als een float
, wat betekent dat het het dubbele aantal cijfers achter de komma kan hebben.