Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Re^2: unintentional conversion of signaling NaN to quiet NaN

by BrowserUk (Patriarch)
on Jun 24, 2016 at 09:19 UTC ( [id://1166474]=note: print w/replies, xml ) Need Help??


in reply to Re: unintentional conversion of signaling NaN to quiet NaN
in thread unintentional conversion of signaling NaN to quiet NaN

I think a perlbug report should be filed for this.

Thing is, there is not a lot that Perl can do about it, as it is the default (and preferred) behaviour for floating point.

In the code below, the bit pattern 0x0x7ff0000000000001 displays as SNaN, only when nothing has caused the value to be loaded into a floating point register.

As soon as the value is loaded into an FP register, it gets silently converted to a QNan; and if the operation causes the result to be stored back to memory, the bit pattern will have been changed to a QNaN pattern.

And, I've tried every combination of Exception Mask bits in the FP control word to change that behaviour and nothing does. I do not see how Perl could change that behaviour outside of emulating FP in software?

Note how both the displayed representation of the value and the bit pattern change as soon as *any* floating point operation is performed on the value:

#include <stdio.h> #include <float.h> typedef union { double d; __int64 i; } BITS64; int main( int argc, char ** argv ) { BITS64 x; __try { _controlfp( _EM_INVALID|_EM_DENORMAL|_EM_ZERODIVIDE|_EM_OVERFL +OW|_EM_UNDERFLOW|_EM_INEXACT, _MCW_EM ); x.i = 0x7ff0000000000001; printf( "as int: %I64u\n", x.i ); printf( "as dbl: %f\n", x.d ); x.d += 0.0; printf( "as dbl: %f\n", x.d ); printf( "as int: %I64u\n", x.i ); } __except( 1 ) { fprintf( stderr, "Exception caught!\n" ); exit( -1 ); } return 0; } /* C:\test>junk.exe as int: 9218868437227405313 as dbl: 1.#SNAN0 as dbl: 1.#QNAN0 as int: 9221120237041090561 */

With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority". I knew I was on the right track :)
In the absence of evidence, opinion is indistinguishable from prejudice. Not understood.

Replies are listed 'Best First'.
Re^3: unintentional conversion of signaling NaN to quiet NaN
by syphilis (Archbishop) on Jun 24, 2016 at 11:35 UTC
    As soon as the value is loaded into an FP register, it gets silently converted to a QNan

    I was thinking that when we do:
    $packed = pack 'd', '7ff0000000000001'; $d = unpack 'h16', $packed;
    there would be no loading of the double into an FP register.
    But I guess that thinking must be wrong as $d is definitely set to '7ff8000000000001', on my Windows box at least.

    On my Linux box (also little-endian), however, there's no such problem and I can assign '7ff0000000000001' just fine.
    Is this difference a Windows v Linux thing ? ... or is it to be explained in terms of different hardware ?

    Do you know of any way that one can assign the value '7ff0000000000001' on Windows ? (I haven't found a way, yet.)

    Here's a nice Perl demo (utilising the union you provided) of the Windows/Linux discrepancy:
    use warnings; use strict; use Inline C => Config => BUILD_NOISY => 1; use Inline C => <<'EOC'; #ifdef _WIN32 typedef __int64 BIGGUN; #else /* "long" is 64-bit on my linux box */ typedef long BIGGUN; #endif typedef union { double d; BIGGUN i; } BITS64; void bytes(double d) { int i; void * p = &d; for(i = 7; i >=0; i--) printf("%02x", ((unsigned char*)p)[i]); printf("\n"); } double get_snan () { BITS64 x; x.i = 0x7ff0000000000001; bytes(x.d); return x.d; } EOC print doubleToHex(get_snan()); sub doubleToHex { scalar reverse unpack 'h16', pack 'd', $_[0] }
    On Windows it outputs:
    7ff0000000000001
    7ff8000000000001

    On Ubuntu it outputs:
    7ff0000000000001
    7ff0000000000001

    Cheers,
    Rob

      Doesn't this work for you?:

      $d = unpack 'd', pack 'Q', 0x7ff0000000000001;; print $d;; 1.#SNAN printf "%f\n", $d;; 1.#SNAN0

      If inline C has to be involved, do it this way:

      #! perl -slw use strict; use Config; use Inline C => Config => BUILD_NOISY => 1; use Inline C => <<'END_C', NAME => 'snanic', CLEAN_AFTER_BUILD =>0; #ifdef _WIN32 typedef __int64 BIGGUN; #else /* "long" is 64-bit on my linux box */ typedef long BIGGUN; #endif typedef union { double d; BIGGUN i; } BITS64; SV*get_snan() { BITS64 x; x.i = 0x7ff0000000000001; return newSVnv( x.d ); } END_C sub doubleToHex { scalar reverse unpack 'h16', pack 'd', $_[0] } my $snan = get_snan(); printf "%f\n", $snan; print doubleToHex( $snan );

      Prints:

      C:\test>snan-ic.pl 1.#SNAN0 7ff0000000000001

      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority". I knew I was on the right track :)
      In the absence of evidence, opinion is indistinguishable from prejudice. Not understood.
        Doesn't this work for you?:

        Well - it doesn't work for me with 32-bit (gcc-5.3.0) builds of perl.
        I was looking at 32-bit perl-5.24.0.:
        C:\_32>perl -V:archname archname='MSWin32-x86-multi-thread-64int'; C:\_32>perl -le "print $]"; 5.024000 C:\_32>perl -le "$d = unpack 'd', pack 'Q', 0x7ff0000000000001;print $ +d; printf '%f', $d;" NaN NaN
        That output doesn't tell us anything about the type of NaN we have. However, POSIX::issignaling tells us that $d is not signalling, and printf '%x\n', unpack 'Q', pack 'd', $d; outputs 7ff8000000000001.

        Things look ok for my 64-bit (gcc-5.3.0) builds of perl.
        With 64-bit perl-5.24.0 the output is the same as just given.
        But this time POSIX::issignaling tells us that $d is signalling and printf '%x\n', unpack 'Q', pack 'd', $d; outputs 7ff0000000000001.

        A regards your Inline::C script, the output is as expected given the above results.
        32-bit perl-5.24.0 ouptuts:
        NaN 7ff8000000000001
        64-bit perl-5.24.0 outputs:
        NaN 7ff0000000000001
        When it comes to Strawberry Perls 5.24.0 (which were built using gcc-4.9.2), I find that both 32-bit and 64-bit are buggy. Your I::C script outputs:
        NaN 7ff8000000000001
        for both.

        I'll try to investigate the problem a little better before I submit any bug reports. It may be that I can tie the behaviour to bugs in the mingw-w64 ports of gcc.

        Cheers,
        Rob

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1166474]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (5)
As of 2024-04-24 22:13 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found