2013-07-30 14 views
5

Ich versuche, in einem Schwimmer zu scannen: 13.8518009935297. Die erste Routine ist meine eigene, die zweite ist MacOSX libc strtod, die dritte ist GMP mpf_get_d() die vierte ist perls numeric.c: Perl_my_atof2().Perl Mantisse unterscheidet sich von anderen Doppel

Ich verwende diese Schnipsel die Mantisse drucken:

union ieee_double { 
     struct { 
       uint32_t fracl; 
       uint32_t frach:20; 
       uint32_t exp:11; 
       uint32_t sign:1; 
     } s; 
     double d; 
     uint64_t l; 
}; 

union ieee_double l0; 
l0.d = .... 
printf("... 0x%x 0x%x\n", l0.s.frach, l0.s.fracl); 

Die Rückgabewerte für die vier Funktionen sind:

my-func : 0xbb41f 0x4283d21b 
strtod : 0xbb41f 0x4283d21c 
GMP  : 0xbb41f 0x4283d21b 
perl : 0xbb41f 0x4283d232 

Der Unterschied zwischen den ersten drei Funktionen rundet. Perls Mantisse ist jedoch ziemlich synchron.

Wenn ich alle vier Doppelter zu einer Zeichenkette wiederdrucke, bekomme ich die gleiche Dezimalzahl doppelt zurück, die Zahlen scheinen gleich zu sein.

Meine Frage: Der Unterschied zwischen my-func, strtod, GMP ist Rundung. Allerdings ist warum ist Perl Mantisse so viel aus der Synchronisation, aber immer noch, wenn zurück in die Dezimalzahl konvertiert, endet es als die gleiche Zahl wieder. Der Unterschied ist 22, so sollte es in einem dezimalen Bruchteil notiert werden. Wie kann ich das erklären?

anhängen: Sorry, ich glaube, ich dachte, das Problem:

$r = rand(25); 
    $t = $p->tokenize_str("$r"); 

tokenize_str() war meine Implementierung einer Umwandlung von Zeichenfolge zu verdoppeln. Allerdings druckt das Perl stringify "$ r" $ r als 13.8518009935297 aus, was bereits eine Kürzung ist. Der tatsächliche Wert von $ r ist anders, also, wenn ich am Ende die Binärdateien von $ t mit $ r bekomme ich Werte, die divergieren.

+2

Laut [dieser Seite] (http://babbage.cs.qc.cuny.edu/IEEE-754.old/64bit.html) hat diese Mantisse tatsächlich 2 Dezimalstellen mehr Dezimalstellen als Sie anzeigen: '13.851800993529700 '. Die Perl-Version entspricht "13.851800993529740". Der Unterschied ist also bei Ihrer Präzision nicht signifikant. Dennoch ist es eine interessante Frage, warum Perl anders ist. –

+0

Entschuldigung, habe den Fehler gefunden (siehe oben). Danke trotzdem für die Antwort ... –

Antwort

0

Hier einige Perl-Code, um Ihre Frage zu beantworten:

perl -le '($frac1, $frach)=unpack("II", pack "d", .0+"13.8518009935297"); 
print sprintf("%d %d 0x%03x 0x%04x", ($frach >> 31)&1, ($frach>>20)&0x5ff, $frach & 0xfffff, $frac1)' 

-> 0 1026 0xbb41f 0x4283d21c

Perl das gleiche Ergebnis wie strtod gibt. Der Unterschied war der Fehler, den Sie in Anhang angegeben haben.

Verwandte Themen