c ++ - Afrundingsforskelle på Windows vs Unix-baserede system i sprintf

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg har et problem på UNIX-baserede systemer sprintf afrunder ikke korrekt værdi.


For eksempel


double tmp = 88888888888885.875
char out[512];


Det er 88.888.888.888.885.875 bare for at være lettere på øjnene.
Jeg giver et sådant specifikt og stort eksempel, fordi det ser ud til, at det fungerer fint på mindre tal.


Jeg forsøger at bruge det på følgende måde


sprintf(out, "\%021.2f", tmp);
printf("out = \%s
", tmp);


På vinduer resulterer dette i:


out = 000088888888888885.88


På for eksempel AIX, men viser også i Linux:


out = 000088888888888885.87


Hvorfor sker det her?
Eventuelle ideer og hvordan man gør det opfører sig på samme måde på Win/Unix


Tak

Bedste reference


Der er en fejlrapport for Glibc med et problem, der ligner din. Hovedkonklusionen (i kommentar 46) her er, at dobbelt er ikke et 15-decimalt tal og du bør ikke forvente, at det fungerer sådan. [11]


Som en løsning kan du tilføje noget lille til dine numre for at gøre dem runde bedre. Men denne løsning er ikke generel, fordi det afhænger af nummerintervaller, du behandler.


En anden løsning kan multiplicere for at forberede dem til afrunding og derefter afrunde (for eksempel 2597.625*100 = 259762.5 -> 259763 = 2597.63*100)


Men jeg synes, at der skal være smartere løsninger.

Andre referencer 1


Hvilke flytende punktpræsentationer bruges af din processor og din kompilator?


Ikke alle processorer bruger samme måde til at repræsentere flydende punktværdier, og selv kompilere kan vælge forskellige flytende punktrepræsentationsmetoder (jeg tror, ​​at Microsoft C ++-kompilatoren selv har muligheder for at vælge repræsentationen).


Siden http://www.quadibloc.com/comp/cp0201.htm giver et overblik over nogle af de flytende punktrepræsentationer (selvom de synes at være temmelig gamle arkitekturer vist der). [12]


http://msdn.microsoft.com/en-us/library/0b34tf65.aspx beskriver, hvordan Microsoft Visual C ++ lagrer flytende punktværdier. Jeg kunne ikke finde ud af, hvilken repræsentation der bruges af AIX eller Linux. [13]


Derudover har hver kompilator indstillinger, som giver dig mulighed for at angive, hvordan du vil arbejde med flydende punktoperationer. Vil du have, at de er korrekte som muligt (men muligvis lidt langsommere)? Eller vil du flydende punkt operationer være hurtig som muligt (men muligvis mindre korrekt)?

Andre referencer 2


Det er fordi du bruger double, som har nøjagtighedsbegrænsninger, hvilket betyder, at din 88888888888885.875 sandsynligvis bliver afrundet til noget andet internt.


Se mere info i et lignende spørgsmål, i blogs eller i wikipedia. [15] [16]

Andre referencer 3


Ved en implementering af IEEE 754-konformet skal den udskrive 88888888888885.88 i standardrundingstilstanden. Dette har intet at gøre med flydende punkt præcision, da værdien er nøjagtigt repræsentativ; det er simpelthen et spørgsmål om printf s afrunding til 2 steder efter decimaltegnet. Ingen ide, hvorfor du ser 88888888888885.87 på nogle systemer.