In <200106040119.CAA10769@crypt.compulink.co.uk>, Hugo writes:
:Nicholas Clark wrote:
::Not sure where to proceed from here - I think it's a gcc or libc issue,
::but as I couldn't make that test fail on long doubles I couldn't track it
::further.
:
:It is a clear bug in glibc modfl:
:
:crypt% cat t0
:#include <math.h>
:#include <stdio.h>
:
:int main(int argc, char** argv) {
: long double nv = 4294967303.15;
: long double v, w;
: v = modfl(nv, &w);
: printf("z = <%Lf> v = <%Lf> w = <%Lf>\n", nv, v, w);
: return 0;
:}
:
:crypt% gcc -o t0 t0.c
:crypt% ./t0
:z = <4294967303.150000> v = <1.150000> w = <4294967302.000000>
:crypt%
:
:(Note that modf() does not exhibit this bug.)
:
:I'll report this, if I can work out where to.
The glibc team report only that it is fixed in the latest version.
:I can't see any easy way for us to work around this.
Here is an easy way for us to work around this. Ideally we'd have
configure support for MODFL_POW32_BUG, but setting it manually
(with Configure -Accflags=-DMODFL_POW32_BUG) allows all tests to
pass here with small ints, long doubles.
For details, see http://bugs.gnu.org/cgi-bin/gnatsweb.pl and look
at bug ids 1548 and 2309.
Hugo
--- pp.c.old Mon Jun 4 00:46:14 2001
+++ pp.c Tue Jun 5 13:16:18 2001
@@ -2598,7 +2598,16 @@
SETu(U_V(value));
} else {
#if defined(HAS_MODFL) || defined(LONG_DOUBLE_EQUALS_DOUBLE)
+# if MODFL_POW32_BUG
+/* some versions of glibc split (i + d) into (i-1, d+1) for 2^32 <= i < 2^64 */
+ {
+ NV offset = Perl_modf(value, &value);
+ (void)Perl_modf(offset, &offset);
+ value += offset;
+ }
+# else
(void)Perl_modf(value, &value);
+# endif
#else
double tmp = (double)value;
(void)Perl_modf(tmp, &tmp);
@@ -2612,7 +2621,16 @@
SETi(I_V(value));
} else {
#if defined(HAS_MODFL) || defined(LONG_DOUBLE_EQUALS_DOUBLE)
+# if MODFL_POW32_BUG
+/* some versions of glibc split (i + d) into (i-1, d+1) for 2^32 <= i < 2^64 */
+ {
+ NV offset = Perl_modf(-value, &value);
+ (void)Perl_modf(offset, &offset);
+ value += offset;
+ }
+# else
(void)Perl_modf(-value, &value);
+# endif
value = -value;
#else
double tmp = (double)value;
Thread Previous
|
Thread Next