Our lrint, llrint, lrintf, llrintf always return 0 for inputs close
to 0.  However, depending on the rounding mode, they should actually
return -1 or 1.

Here's my test case:

#include <ieeefp.h>
#include <math.h>
#include <stdio.h>

int
main(void)
{
        fpsetround(FP_RM);
        printf("%ld\n", lrint(-0.2));
        fpsetround(FP_RP);
        printf("%ld\n", lrint(0.2));
        return (0);
}

It returns zero, however they should actually be -1, and 1.  The
assumption that |1.0 * 2^exp| = 0, exp < -1 cannot be made when we
round towards -inf or +inf.

If you're testing it on amd64 or i386 please note, that those
platforms are not affected--they use the assembly versions which do
the right thing.

Index: s_lrint.c
===================================================================
RCS file: /cvs/src/lib/libm/src/s_lrint.c,v
retrieving revision 1.1
diff -u -r1.1 s_lrint.c
--- s_lrint.c   25 Sep 2006 20:25:41 -0000      1.1
+++ s_lrint.c   7 Apr 2011 01:07:20 -0000
@@ -61,9 +61,6 @@
        s = e >> DBL_EXPBITS;
        e = (e & 0x7ff) - DBL_EXP_BIAS;

-       /* 1.0 x 2^-1 is the smallest number which can be rounded to 1 */
-       if (e < -1)
-               return (0);
        /* 1.0 x 2^31 (or 2^63) is already too large */
        if (e >= (int)RESTYPE_BITS - 1)
                return (s ? RESTYPE_MIN : RESTYPE_MAX); /* ??? unspecified */
@@ -79,6 +76,9 @@
        e = ((i0 >> 20) & 0x7ff) - DBL_EXP_BIAS;
        i0 &= 0xfffff;
        i0 |= (1 << 20);
+
+       if (e < 0)
+               return (0);

        shift = e - DBL_FRACBITS;
        if (shift >=0)
Index: s_lrintf.c
===================================================================
RCS file: /cvs/src/lib/libm/src/s_lrintf.c,v
retrieving revision 1.1
diff -u -r1.1 s_lrintf.c
--- s_lrintf.c  25 Sep 2006 20:25:41 -0000      1.1
+++ s_lrintf.c  7 Apr 2011 01:10:19 -0000
@@ -61,9 +61,6 @@
        s = e >> SNG_EXPBITS;
        e = (e & 0xff) - SNG_EXP_BIAS;

-       /* 1.0 x 2^-1 is the smallest number which can be rounded to 1 */
-       if (e < -1)
-               return (0);
        /* 1.0 x 2^31 (or 2^63) is already too large */
        if (e >= (int)RESTYPE_BITS - 1)
                return (s ? RESTYPE_MIN : RESTYPE_MAX); /* ??? unspecified */
@@ -81,6 +78,9 @@
        e = ((i0 >> SNG_FRACBITS) & 0xff) - SNG_EXP_BIAS;
        i0 &= 0x7fffff;
        i0 |= (1 << SNG_FRACBITS);
+
+       if (e < 0)
+               return (0);

        shift = e - SNG_FRACBITS;
        if (shift >=0)

Reply via email to