2013-07-30 26 views
5

Próbuję skanować w float: 13.8518009935297. Pierwsza rutyna jest moja, druga to MacOSX libc: strtod, trzecia to GMP's mpf_get_d() czwarta to perls numeric.c: Perl_my_atof2().Maniak perłowy różni się od innych debli

Używam tego fragmentu kodu, aby wydrukować mantysę:

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

Wartości zamian za cztery funkcje:

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

Różnica między pierwszymi trzema funkcjami jest zaokrąglania. Jednak mancha perla jest dość niezsynchronizowana.

Jeśli ponownie wydrukuję wszystkie cztery duble w ciągu, otrzymam to samo dziesiętne podwójne odbicie, liczby wydają się być jednakowe.

Moje pytanie: Różnica między my-func, strtod, GMP jest zaokrąglana. Jednak, , dlaczego mancha perla jest tak bardzo niezsynchronizowana, ale nadal, jeśli z powrotem do dziesiętnych, kończy się jako ta sama liczba ponownie. Różnica wynosi 22, więc należy oznaczyć ją jako ułamek dziesiętny . Jak mogę to wyjaśnić?

Dołącz: Niestety, myślę, że zorientowali się problem:

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

tokenize_str() była moja realizacja konwersji z ciągiem do podwójnie. Jednak string stringi "$ r" wypisuje $ r jako 13.8518009935297, czyli już obcięte, czyli . Rzeczywista wartość $ r jest różna, więc kiedy na końcu binarki z $ t z $ r otrzymuję wartości, które rozchodzą się.

+2

Zgodnie z [tą stroną] (http://babbage.cs.qc.cuny.edu/IEEE-754.old/64bit.html), mantysta ma dokładność dokładności dziesiętnej o 2 kolejne cyfry, niż pokazano: "13.851800993529700 '. Wersja Perla to "13.851800993529740". Tak więc różnica nie jest znacząca na twoim poziomie precyzji. Nadal jest to interesujące pytanie, dlaczego Perl jest inny. –

+0

Przepraszamy, ustaliliśmy błąd (patrz wyżej). Mimo to dzięki za odpowiedź ... –

Odpowiedz

0

Oto kod Perl odpowiedzieć na pytanie:

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 daje taki sam wynik jak strtod. Różnica polegała na tym, że wskazałeś błąd w dołączeniu.