pryrt has asked for the wisdom of the Perl Monks concerning the following question:
Harkening back to my experiments to make an Expand.pm to interpret IEEE754 doubles, I found when making my tests that as I converted a signaling NaN bit string into a double then back to the bit string, it became a quiet NaN. At first I thought I just had a bug in my conversion, so then I tried BrowserUK's code from Re^2: Exploring IEEE754 floating point bit patterns., along with a new function to convert it back.
#!/usr/bin/perl use warnings; use strict; use lib '.'; use Tools; # local == Data::IEEE754::Tools use constant { POS_ZERO => '0'.'00000000000'.'0000'.'00000000'.'00000000'. +'00000000'.'00000000'.'00000000'.'00000000', POS_DENORM_1ST => '0'.'00000000000'.'0000'.'00000000'.'00000000'. +'00000000'.'00000000'.'00000000'.'00000001', POS_DENORM_LST => '0'.'00000000000'.'1111'.'11111111'.'11111111'. +'11111111'.'11111111'.'11111111'.'11111111', POS_NORM_1ST => '0'.'00000000001'.'0000'.'00000000'.'00000000'. +'00000000'.'00000000'.'00000000'.'00000000', POS_NORM_LST => '0'.'11111111110'.'1111'.'11111111'.'11111111'. +'11111111'.'11111111'.'11111111'.'11111111', POS_INF => '0'.'11111111111'.'0000'.'00000000'.'00000000'. +'00000000'.'00000000'.'00000000'.'00000000', POS_SNAN_1ST => '0'.'11111111111'.'0000'.'00000000'.'00000000'. +'00000000'.'00000000'.'00000000'.'00000001', POS_SNAN_LST => '0'.'11111111111'.'0111'.'11111111'.'11111111'. +'11111111'.'11111111'.'11111111'.'11111111', POS_IND => '0'.'11111111111'.'1000'.'00000000'.'00000000'. +'00000000'.'00000000'.'00000000'.'00000000', POS_QNAN_1ST => '0'.'11111111111'.'1000'.'00000000'.'00000000'. +'00000000'.'00000000'.'00000000'.'00000001', POS_QNAN_LST => '0'.'11111111111'.'1111'.'11111111'.'11111111'. +'11111111'.'11111111'.'11111111'.'11111111', NEG_ZERO => '1'.'00000000000'.'0000'.'00000000'.'00000000'. +'00000000'.'00000000'.'00000000'.'00000000', NEG_DENORM_1ST => '1'.'00000000000'.'0000'.'00000000'.'00000000'. +'00000000'.'00000000'.'00000000'.'00000001', NEG_DENORM_LST => '1'.'00000000000'.'1111'.'11111111'.'11111111'. +'11111111'.'11111111'.'11111111'.'11111111', NEG_NORM_1ST => '1'.'00000000001'.'0000'.'00000000'.'00000000'. +'00000000'.'00000000'.'00000000'.'00000000', NEG_NORM_LST => '1'.'11111111110'.'1111'.'11111111'.'11111111'. +'11111111'.'11111111'.'11111111'.'11111111', NEG_INF => '1'.'11111111111'.'0000'.'00000000'.'00000000'. +'00000000'.'00000000'.'00000000'.'00000000', NEG_SNAN_1ST => '1'.'11111111111'.'0000'.'00000000'.'00000000'. +'00000000'.'00000000'.'00000000'.'00000001', NEG_SNAN_LST => '1'.'11111111111'.'0111'.'11111111'.'11111111'. +'11111111'.'11111111'.'11111111'.'11111111', NEG_IND => '1'.'11111111111'.'1000'.'00000000'.'00000000'. +'00000000'.'00000000'.'00000000'.'00000000', NEG_QNAN_1ST => '1'.'11111111111'.'1000'.'00000000'.'00000000'. +'00000000'.'00000000'.'00000000'.'00000001', NEG_QNAN_LST => '1'.'11111111111'.'1111'.'11111111'.'11111111'. +'11111111'.'11111111'.'11111111'.'11111111', }; my @list = ( POS_ZERO, POS_DENORM_1ST, POS_DENORM_LST, POS_NORM_1ST, POS_NORM_L +ST, POS_INF, POS_SNAN_1ST, POS_SNAN_LST, POS_IND, POS_QNAN_1ST, POS_QNAN_LST, NEG_ZERO, NEG_DENORM_1ST, NEG_DENORM_LST, NEG_NORM_1ST, NEG_NORM_L +ST, NEG_INF, NEG_SNAN_1ST, NEG_SNAN_LST, NEG_IND, NEG_QNAN_1ST, NEG_QNAN_LST ); sub bitsToDouble{ unpack 'd', pack 'b64', scalar reverse $_[0] } sub bitsToInts{ reverse unpack 'VV', pack 'b64', scalar reverse $_[0 +] } sub doubleToBits{ scalar reverse unpack 'b64', pack 'd', $_[0] } printf "%23.16g : %08x%08x >=there-and-back-again=> %08x%08x\n", bitsToDouble( $_ ), bitsToInts( $_ ), bitsToInts( doubleToBits( bitsToDouble( $_ ) ) ) for @list; print "\n"; use Test::More tests => 22; is( doubleToBits( bitsToDouble( $_ ) ) , $_ , "bitsToDouble(doubleToBi +ts($_))" ) for @list;
outputs
0 : 0000000000000000 >=there-and-back-again=> 00 +00000000000000 4.940656458412465e-324 : 0000000000000001 >=there-and-back-again=> 00 +00000000000001 2.225073858507201e-308 : 000fffffffffffff >=there-and-back-again=> 00 +0fffffffffffff 2.225073858507201e-308 : 0010000000000000 >=there-and-back-again=> 00 +10000000000000 1.797693134862316e+308 : 7fefffffffffffff >=there-and-back-again=> 7f +efffffffffffff Inf : 7ff0000000000000 >=there-and-back-again=> 7f +f0000000000000 NaN : 7ff0000000000001 >=there-and-back-again=> 7f +f8000000000001 NaN : 7ff7ffffffffffff >=there-and-back-again=> 7f +ffffffffffffff NaN : 7ff8000000000000 >=there-and-back-again=> 7f +f8000000000000 NaN : 7ff8000000000001 >=there-and-back-again=> 7f +f8000000000001 NaN : 7fffffffffffffff >=there-and-back-again=> 7f +ffffffffffffff -0 : 8000000000000000 >=there-and-back-again=> 80 +00000000000000 -4.940656458412465e-324 : 8000000000000001 >=there-and-back-again=> 80 +00000000000001 -2.225073858507201e-308 : 800fffffffffffff >=there-and-back-again=> 80 +0fffffffffffff -2.225073858507201e-308 : 8010000000000000 >=there-and-back-again=> 80 +10000000000000 -1.797693134862316e+308 : ffefffffffffffff >=there-and-back-again=> ff +efffffffffffff -Inf : fff0000000000000 >=there-and-back-again=> ff +f0000000000000 NaN : fff0000000000001 >=there-and-back-again=> ff +f8000000000001 NaN : fff7ffffffffffff >=there-and-back-again=> ff +ffffffffffffff NaN : fff8000000000000 >=there-and-back-again=> ff +f8000000000000 NaN : fff8000000000001 >=there-and-back-again=> ff +f8000000000001 NaN : ffffffffffffffff >=there-and-back-again=> ff +ffffffffffffff ... not ok 7 - bitsToDouble(doubleToBits(011111111111000000000000000000000 +0000000000000000000000000000001)) # Failed test 'bitsToDouble(doubleToBits(011111111111000000000000000 +0000000000000000000000000000000000001))' # at ...\buk.pl line 52. # got: '01111111111110000000000000000000000000000000000000000 +00000000001' # expected: '01111111111100000000000000000000000000000000000000000 +00000000001' not ok 8 - bitsToDouble(doubleToBits(011111111111011111111111111111111 +1111111111111111111111111111111)) # Failed test 'bitsToDouble(doubleToBits(011111111111011111111111111 +1111111111111111111111111111111111111))' # at ...\buk.pl line 52. # got: '01111111111111111111111111111111111111111111111111111 +11111111111' # expected: '01111111111101111111111111111111111111111111111111111 +11111111111' ... not ok 18 - bitsToDouble(doubleToBits(11111111111100000000000000000000 +00000000000000000000000000000001)) # Failed test 'bitsToDouble(doubleToBits(111111111111000000000000000 +0000000000000000000000000000000000001))' # at ...\buk.pl line 52. # got: '11111111111110000000000000000000000000000000000000000 +00000000001' # expected: '11111111111100000000000000000000000000000000000000000 +00000000001' not ok 19 - bitsToDouble(doubleToBits(11111111111101111111111111111111 +11111111111111111111111111111111)) # Failed test 'bitsToDouble(doubleToBits(111111111111011111111111111 +1111111111111111111111111111111111111))' # at ...\buk.pl line 52. # got: '11111111111111111111111111111111111111111111111111111 +11111111111' # expected: '11111111111101111111111111111111111111111111111111111 +11111111111' ...
... ie, it fails on just the signaling NaN, appearing like a quiet NaN bitstring.
I tried under an ancient CentOS 4.6 perl 5.8.5, and under a recent Strawberry 5.22.1 32bit, and get the same quieting of the sNaN. Am I doing something wrong, or does perl just automatically quiet signalling NaN values?
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: unintentional conversion of signaling NaN to quiet NaN
by BrowserUk (Patriarch) on Jun 23, 2016 at 21:41 UTC | |
by pryrt (Abbot) on Jun 23, 2016 at 23:44 UTC | |
Re: unintentional conversion of signaling NaN to quiet NaN
by syphilis (Archbishop) on Jun 24, 2016 at 08:09 UTC | |
by BrowserUk (Patriarch) on Jun 24, 2016 at 09:19 UTC | |
by syphilis (Archbishop) on Jun 24, 2016 at 11:35 UTC | |
by BrowserUk (Patriarch) on Jun 24, 2016 at 17:31 UTC | |
by syphilis (Archbishop) on Jun 25, 2016 at 11:00 UTC | |
|