/* Need -0.0 for SvNVX to preserve IEEE FP "negative zero" because
+0.0 + -0.0 => +0.0 but -0.0 + -0.0 => -0.0 */
# define SvIVX(sv) (0 + ((XPVIV*) SvANY(sv))->xiv_iv)
# define SvUVX(sv) (0 + ((XPVUV*) SvANY(sv))->xuv_uv)
# define SvNVX(sv) (-0.0 + ((XPVNV*) SvANY(sv))->xnv_u.xnv_nv)
Their attempts to "preserve IEEE FP "negative zero"", performs + -0.0, which will *always* force SNaN to QNaN.
That said, there is conditional code for the 'F' and 'D' templates in pp_pack.c that bypasses SvNV (which uses SvNVX() if SvNOK is set) in favour of sv_2nv(), which ought to kick in on mingw builds: #ifdef __GNUC__
/* to work round a gcc/x86 bug; don't use SvNV */
anv.nv = sv_2nv(fromstr);
#else
anv.nv = SvNV(fromstr);
#endif
But that conditional is not present in 'd' template.
And in any case, sv_2nv() goes right ahead and uses SvNVX() if SvNOKp is set anyway: Perl_sv_2nv_flags(pTHX_ SV *const sv, const I32 flags)
{
dVAR;
if (!sv)
return 0.0;
if (SvGMAGICAL(sv) || SvVALID(sv) || isREGEXP(sv)) {
/* FBMs use the space for SvIVX and SvNVX for other purposes, and
+use
the same flag bit as SVf_IVisUV, so must not let them cache NVs
+.
Regexps have no SvIVX and SvNVX fields. */
const char *ptr;
if (flags & SV_GMAGIC)
mg_get(sv);
if (SvNOKp(sv))
return SvNVX(sv);
so I don't quite see what purpose the conditional code above achieves ?
Bottom line: There is a bug -- or a combination of bugs -- that is preventing you getting your hands on an SNAN; but I don't think that it will be a quick fix.
Your best bet if you want to 'cure' the problem yourself is to bypass the Perl macros completely. The following won't work pre-5.10, and may not work on some later builds. (The latest version of 32-bit perl I have with inline installed is 5.8.9 and it doesn't work there.) And remember, if you touch the returned value with pack it will probably screw with it again. : #! 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*get_snan() {
SV *nv = newSVnv(0.0);
*(unsigned __int64*)&( ((XPVNV*) SvANY(nv))->xnv_u.xnv_nv ) = i;
return nv;
}
END_C
sub doubleToHex { scalar reverse unpack 'h16', pack 'd', $_[0] }
my $snan = get_snan();
printf "%f\n", $snan;
print doubleToHex( $snan );
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.
In the absence of evidence, opinion is indistinguishable from prejudice. Not understood.
|