2013-07-30 10 views
5

Sto provando a scansionare in un float: 13.8518009935297. La prima routine è la mia, la seconda è lo strtod di MacOSX libc, la terza è mpf_get_d() di GMP la quarta è perls numeric.c: Perl_my_atof2().Perissa mantissa differisce dagli altri doppi

Io uso questo frammento stampare la mantissa:

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); 

I valori di ritorno per le quattro funzioni sono:

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

La differenza tra i primi tre funzioni è arrotondamento. Tuttavia la mantissa di perl è abbastanza fuori sincrono.

Se stampo nuovamente tutti e quattro i doppi in una stringa, ottengo lo stesso dorso doppio decimale , i numeri sembrano uguali.

La mia domanda: La differenza tra my-func, strtod, GMP sta arrotondando. Tuttavia, perché la mantissa di perl è così fuori sincrono, ma comunque, se viene convertita nuovamente in decimale, finisce con lo stesso numero di nuovo. La differenza è 22, quindi dovrebbe essere annotata in una frazione decimale . Come posso spiegarlo?

Aggiungi: dispiace, credo di aver capito il problema:

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

tokenize_str() è stata la mia realizzazione di una conversione da stringa a raddoppiare. Tuttavia il perl stringify "$ r" stampa $ r come 13.8518009935297, che è già un troncamento . Il valore effettivo di $ r è diverso, quindi quando alla fine i binari di $ t con $ r ottengo valori divergenti.

+2

Secondo [questa pagina] (http://babbage.cs.qc.cuny.edu/IEEE-754.old/64bit.html), quella mantissa ha in realtà 2 cifre decimali in più rispetto a quella mostrata: '13.851800993529700 '. La versione Perl è uguale a '13.851800993529740'. Quindi la differenza non è significativa al tuo livello di precisione. Eppure, è una domanda interessante perché Perl è diverso. –

+0

Siamo spiacenti, ho capito l'errore (vedi sopra). Grazie comunque per la risposta ... –

risposta

0

Ecco il codice Perl per rispondere alla tua domanda:

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 dà lo stesso risultato di strtod. La differenza è stata l'errore che hai indicato in append.