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

Their attempts to "preserve IEEE FP "negative zero"", performs + -0.0, which will *always* force SNaN to QNaN

Yes - that does seem pretty general behaviour, but I'm not concerned about that.
In fact, I've come to the view that if an operation involving an SNAN does not throw an exception then the result might just as well be a QNAN - since the SNAN is effectively quiet anyway.
Perhaps that's the rationale behind the behaviour.

I see no reason to expect that an operation involving an SNAN cannot not return a QNAN when no exception is thrown and I can even see a case for propagating the SNAN as a QNAN.
However, I don't know what the relevant IEEE standards stipulate - and, obviously if this behaviour contravenes said standards then the behaviour should be changed.

The following won't work pre-5.10, and may not work on some later builds

On 32-bit 5.22.0, 5.24.0 and latest blead the NV still gets set to 7ff8000000000001. (I didn't try any other perl versions.)

I don't personally need to be able to assign a double with internal representation of 7ff0000000000001, though I do think it's at least worth raising awareness of this bug in the 32-bit Windows builds.
But first I'll make a concerted effort to find a way to make that assignment.

Cheers,
Rob
  • Comment on Re^7: unintentional conversion of signaling NaN to quiet NaN

Replies are listed 'Best First'.
Re^8: unintentional conversion of signaling NaN to quiet NaN
by BrowserUk (Patriarch) on Jun 26, 2016 at 08:15 UTC

    You miss my point; or more likely I didn't make it clear enough.

    The point is that it is trivial to assign a signalling NaN to an NV; the problem arises when you try to verify/prove that you've done so. because having got the value in there, in order to access it, almost any code you use to get access to the NV (including unpack), will use SvNVX(), and that macro performs the (pointless) floating point addition, which will mean the SNaN will have been coerced to a QNaN before you can check that the assignment was successful; thus you will forever think the assignment failed, when in fact it succeeded, and it is only the attempt to verify it fails.

    Though I suppose another view might be: can you judge the assignment to be successful, if you can never get the value you assigned, back, without it having been corrupted.

    Either of these should produce an SNaN under 32-bit:

    printf "%f\n", unpack 'd', pack 'VV', 0x00000001, 0x7FF00000;; 1.#QNAN0 printf "%f\n", unpack 'F', pack 'VV', 0x00000001, 0x7FF00000;; 1.#QNAN0

    They don't, because the unpack (via the SvNVX() macro) adds -0.0 to the value generated by the pack. And that's a bug.


    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.
      Though I suppose another view might be: can you judge the assignment to be successful, if you can never get the value you assigned, back, without it having been corrupted.

      Yes - how do we conclusively determine whether the bug is in the assigning, or in the retrieving ?
      I've been approaching this in a number of different ways, using POSIX, Inline::C and pack/unpack and it's always the same result.
      On the x86 perl, whenever I check the value of the (supposed) SNAN, the output tells me that it's a QNAN. Yet the x64 perl always produces expected results.
      It's very strange that identical code that behaves fine on x64 perl breaks on x86 perl - given that both of those perls have an ivtype of "long long" and an nvtype of "double".

      Just now I've built x86 latest blead (5.25.2) with SvNVX() modified such that the addition of -0.0 is removed.
      But it has made no difference.

      However, I notice that the SvNVX macro that adds -0.0 is in an #ifdef PERL_DEBUG_COW block and I don't know if PERL_DEBUG_COW is defined.
      I suspect that it's not defined because the test suite still produces the same results.

      I should just file the bug report and let 'em work it out.

      Cheers,
      Rob
        Yes - how do we conclusively determine whether the bug is in the assigning, or in the retrieving ?

        The best I can think of is the IC code below. It returns an SV that has SvNOK set and the NV contains an SNaN bit pattern.

        It does two things that are a bit trick (and non-portable to earlier (<5.10) builds because of changes to perl's internal structures over the last several builds.)

        1. It assigns the bit pattern to the NV field of the SV directly, bypassing any/all internal macros that might mess with it.
        2. It points the PV pointer at the memory containing the NV allowing direct access from perl without unpack 'd'/'F'

        It *may* be possible to port it to gcc/32-bit?

        #! perl -slw use strict; use Config; use Inline C => Config => BUILD_NOISY => 1, CCFLAGS => $Config{ccflags +}." -DDEBUG=1"; use Inline C => <<'END_C', NAME => 'ICexample', CLEAN_AFTER_BUILD =>0 +; static const unsigned __int64 i = 0x7ff0000000000001; SV*snan2() { // Allocate a new SvPV with some junk pv data SV *ret = newSVpvn( "JustJunk", 8 ); // Assign the SNaN bit pattern directly to the NV field bypassing +any dodgy macros *(unsigned __int64*)&( ( (XPVNV*)ret->sv_any )->xnv_u.xnv_nv ) = i +; // Set the NOK flag SvNOK_on( ret ); // Now point the PV pointer directly at the NV memory so we can ac +cess it // (the NV) from perl without going through pack 'd'/'F' SvPV_set( ret, (char*)&( ( (XPVNV*)ret->sv_any )->xnv_u.xnv_nv ) ) +; // make it persist SvREFCNT_inc_void_NN( ret ); // Make sure noone can mess with it. SvREADONLY( ret ); return ret; } END_C ## Get an SNAN. my $snan2 = snan2(); ##Print its numeric value AND its bit pattern bypassing SVNV?() printf "%f\n%x\n", $snan2, unpack 'Q', $snan2; ## Same thing as the printf '%x', unpack 'Q' above ## that *might* work on 32-bit that doesn't have Q print scalar reverse unpack 'h*', $snan2; __END__ C:\test>snan-ic.pl 1.#SNAN0 7ff0000000000001 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.