develooper Front page | perl.perl5.porters | Postings from March 2006

revisited: pow.t test failures on AIX 5.1 perl588 with -Duselongdouble

Thread Next
From:
John L. Allen
Date:
March 30, 2006 14:53
Subject:
revisited: pow.t test failures on AIX 5.1 perl588 with -Duselongdouble
Message ID:
Pine.GSO.4.53.0603301710140.24672@gateway.northropgrumman.com

Well, it's three+ weeks since I reported the powl() bug to IBM, and of
course they have not provided a fix yet, so I was forced to write the
following patch to pp.c.  Hopefully it conforms to everyone's patching
standards - I did my best.  The extra code to make powl() work correctly
is only compiled in when both USE_LONG_DOUBLE and
HAS_AIX_POWL_NEG_BASE_BUG are set.  Nicholas Clark's intent was to
provide a Configure probe to look for the problem and set
HAS_AIX_POWL_NEG_BASE_BUG if found.  I wrote a short C program to evince
the bug in a prior thread.  I hope it can still be integrated into
Configure.  I'll be happy to test it.

As for this patch to pp.c, my only regret is that I call fmod() to
determine if the exponent is an odd/even integer.  If someone knows a
better way, please chime in, but be aware that it has to work for
long double "integers" too large to fit in a long long integer.

There is one other change I'd like to make: that is, to t/op/pow.t.  In
order for it to be a able to uncover this problem, it needs to raise -3 to
a power higher than 32.  Currently it tops out at -3**29 because of not
wanting to produce a result greater than 2**48 for Cray's benefit.  What
is the best way to skip such higher power tests on a Cray?

Here's the gdiff -u patch:

--- pp.c.orig	Sun Jan  8 15:58:55 2006
+++ pp.c	Thu Mar 30 16:35:36 2006
@@ -1014,7 +1014,47 @@
 #endif
     {
 	dPOPTOPnnrl;
+
+#if defined(USE_LONG_DOUBLE) && defined(HAS_AIX_POWL_NEG_BASE_BUG)
+    /*
+    We are building perl with long double support and are on an AIX OS
+    afflicted with a powl() function that wrongly returns NaNQ for any
+    negative base.  This was reported to IBM as PMR #23047-379 on
+    03/06/2006.  The problem exists in at least the following versions
+    of AIX and the libm fileset, and no doubt others as well:
+
+	AIX 4.3.3-ML10      bos.adt.libm 4.3.3.50
+	AIX 5.1.0-ML04      bos.adt.libm 5.1.0.29
+	AIX 5.2.0           bos.adt.libm 5.2.0.85
+
+    So, until IBM fixes powl(), we provide the following workaround to
+    handle the problem ourselves.  Our logic is as follows: for
+    negative bases (left), we use fmod(right, 2) to check if the
+    exponent is an odd or even integer:
+
+	- if odd,  powl(left, right) == -powl(-left, right)
+	- if even, powl(left, right) ==  powl(-left, right)
+
+    If the exponent is not an integer, the result is rightly NaNQ, so
+    we just return that (as NV_NAN).
+    */
+
+	if (left < 0.0) {
+	    NV mod2 = Perl_fmod( right, 2.0 );
+	    if (mod2 == 1.0 || mod2 == -1.0) {	/* odd integer */
+		SETn( -Perl_pow( -left, right) );
+	    } else if (mod2 == 0.0) {		/* even integer */
+		SETn( Perl_pow( -left, right) );
+	    } else {				/* fractional power */
+		SETn( NV_NAN );
+	    }
+	} else {
+	    SETn( Perl_pow( left, right) );
+	}
+#else
 	SETn( Perl_pow( left, right) );
+#endif  /* HAS_AIX_POWL_NEG_BASE_BUG */
+
 #ifdef PERL_PRESERVE_IVUV
 	if (is_int)
 	    SvIV_please(TOPs);

Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About