From f8ba1b5654d876c8db4c9a020e6fa976d434f988 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Tue, 10 Jun 2014 12:07:15 +0000 Subject: [PATCH] Fix log2 (1) in round-downward mode (bug 17042). As with other issues of this kind, bug 17042 is log2 (1) wrongly returning -0 instead of +0 in round-downward mode because of implementations effectively in terms of log1p (x - 1). This patch fixes the issue in the same way used for log and log10. Tested x86_64 and x86 and ulps updated accordingly. Also tested for mips64 to confirm a fix was needed for ldbl-128 and to validate that fix (also applied to ldbl-128ibm since that version of log2l is essentially the same as the ldbl-128 one). [BZ #17042] * sysdeps/i386/fpu/e_log2.S (__ieee754_log2): Take absolete value when x - 1 is zero. * sysdeps/i386/fpu/e_log2f.S (__ieee754_log2f): Likewise. * sysdeps/i386/fpu/e_log2l.S (__ieee754_log2l): Likewise. * sysdeps/ieee754/ldbl-128/e_log2l.c (__ieee754_log2l): Return 0.0L for an argument of 1.0L. * sysdeps/ieee754/ldbl-128ibm/e_log2l.c (__ieee754_log2l): Likewise. * sysdeps/x86_64/fpu/e_log2l.S (__ieee754_log2l): Take absolute value when x - 1 is zero. * math/libm-test.inc (log2_test): Use ALL_RM_TEST. * sysdeps/i386/fpu/libm-test-ulps: Update. * sysdeps/x86_64/fpu/libm-test-ulps: Likewise. --- ChangeLog | 17 +++++++++++++++++ NEWS | 2 +- math/libm-test.inc | 4 +--- sysdeps/i386/fpu/e_log2.S | 8 +++++++- sysdeps/i386/fpu/e_log2f.S | 8 +++++++- sysdeps/i386/fpu/e_log2l.S | 8 +++++++- sysdeps/i386/fpu/libm-test-ulps | 16 ++++++++++++++++ sysdeps/ieee754/ldbl-128/e_log2l.c | 3 +++ sysdeps/ieee754/ldbl-128ibm/e_log2l.c | 3 +++ sysdeps/x86_64/fpu/e_log2l.S | 8 +++++++- sysdeps/x86_64/fpu/libm-test-ulps | 22 ++++++++++++++++++++++ 11 files changed, 91 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0ace298b9e..9055159cf0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2014-06-10 Joseph Myers + + [BZ #17042] + * sysdeps/i386/fpu/e_log2.S (__ieee754_log2): Take absolete value + when x - 1 is zero. + * sysdeps/i386/fpu/e_log2f.S (__ieee754_log2f): Likewise. + * sysdeps/i386/fpu/e_log2l.S (__ieee754_log2l): Likewise. + * sysdeps/ieee754/ldbl-128/e_log2l.c (__ieee754_log2l): Return + 0.0L for an argument of 1.0L. + * sysdeps/ieee754/ldbl-128ibm/e_log2l.c (__ieee754_log2l): + Likewise. + * sysdeps/x86_64/fpu/e_log2l.S (__ieee754_log2l): Take absolute + value when x - 1 is zero. + * math/libm-test.inc (log2_test): Use ALL_RM_TEST. + * sysdeps/i386/fpu/libm-test-ulps: Update. + * sysdeps/x86_64/fpu/libm-test-ulps: Likewise. + 2014-06-09 Bernard Ogden [BZ #15119] diff --git a/NEWS b/NEWS index 622cdbf21d..ca3ef633b0 100644 --- a/NEWS +++ b/NEWS @@ -19,7 +19,7 @@ Version 2.20 16791, 16796, 16799, 16800, 16815, 16823, 16824, 16831, 16838, 16849, 16854, 16876, 16877, 16878, 16882, 16885, 16888, 16890, 16912, 16915, 16916, 16917, 16922, 16927, 16928, 16932, 16943, 16958, 16965, 16966, - 16967, 16977, 16978, 16984, 16990, 17009. + 16967, 16977, 16978, 16984, 16990, 17009, 17042. * The minimum Linux kernel version that this version of the GNU C Library can be used with is 2.6.32. diff --git a/math/libm-test.inc b/math/libm-test.inc index 0d467a2195..fa8e2385dc 100644 --- a/math/libm-test.inc +++ b/math/libm-test.inc @@ -7840,9 +7840,7 @@ static const struct test_f_f_data log2_test_data[] = static void log2_test (void) { - START (log2, 0); - RUN_TEST_LOOP_f_f (log2, log2_test_data, ); - END; + ALL_RM_TEST (log2, 0, log2_test_data, RUN_TEST_LOOP_f_f, END); } diff --git a/sysdeps/i386/fpu/e_log2.S b/sysdeps/i386/fpu/e_log2.S index a202bc731d..73ff0fffd3 100644 --- a/sysdeps/i386/fpu/e_log2.S +++ b/sysdeps/i386/fpu/e_log2.S @@ -47,7 +47,13 @@ ENTRY(__ieee754_log2) fnstsw // x-1 : x : 1 andb $0x45, %ah jz 2f - fstp %st(1) // x-1 : 1 + fxam + fnstsw + andb $0x45, %ah + cmpb $0x40, %ah + jne 5f + fabs // log2(1) is +0 in all rounding modes. +5: fstp %st(1) // x-1 : 1 fyl2xp1 // log(x) ret diff --git a/sysdeps/i386/fpu/e_log2f.S b/sysdeps/i386/fpu/e_log2f.S index f4f9a8c3bf..344eeb495e 100644 --- a/sysdeps/i386/fpu/e_log2f.S +++ b/sysdeps/i386/fpu/e_log2f.S @@ -47,7 +47,13 @@ ENTRY(__ieee754_log2f) fnstsw // x-1 : x : 1 andb $0x45, %ah jz 2f - fstp %st(1) // x-1 : 1 + fxam + fnstsw + andb $0x45, %ah + cmpb $0x40, %ah + jne 5f + fabs // log2(1) is +0 in all rounding modes. +5: fstp %st(1) // x-1 : 1 fyl2xp1 // log(x) ret diff --git a/sysdeps/i386/fpu/e_log2l.S b/sysdeps/i386/fpu/e_log2l.S index bd51b5651e..0f5f7e5789 100644 --- a/sysdeps/i386/fpu/e_log2l.S +++ b/sysdeps/i386/fpu/e_log2l.S @@ -47,7 +47,13 @@ ENTRY(__ieee754_log2l) fnstsw // x-1 : x : 1 andb $0x45, %ah jz 2f - fstp %st(1) // x-1 : 1 + fxam + fnstsw + andb $0x45, %ah + cmpb $0x40, %ah + jne 5f + fabs // log2(1) is +0 in all rounding modes. +5: fstp %st(1) // x-1 : 1 fyl2xp1 // log(x) ret diff --git a/sysdeps/i386/fpu/libm-test-ulps b/sysdeps/i386/fpu/libm-test-ulps index 1e89284455..d7424a6f86 100644 --- a/sysdeps/i386/fpu/libm-test-ulps +++ b/sysdeps/i386/fpu/libm-test-ulps @@ -1588,6 +1588,22 @@ ifloat: 1 ildouble: 1 ldouble: 1 +Function: "log2_towardzero": +double: 1 +float: 1 +idouble: 1 +ifloat: 1 +ildouble: 1 +ldouble: 1 + +Function: "log2_upward": +double: 1 +float: 1 +idouble: 1 +ifloat: 1 +ildouble: 1 +ldouble: 1 + Function: "log_downward": ildouble: 1 ldouble: 1 diff --git a/sysdeps/ieee754/ldbl-128/e_log2l.c b/sysdeps/ieee754/ldbl-128/e_log2l.c index 6c7da0e44b..991a3b73e2 100644 --- a/sysdeps/ieee754/ldbl-128/e_log2l.c +++ b/sysdeps/ieee754/ldbl-128/e_log2l.c @@ -188,6 +188,9 @@ __ieee754_log2l (x) if (hx >= 0x7fff000000000000LL) return (x + x); + if (x == 1.0L) + return 0.0L; + /* separate mantissa from exponent */ /* Note, frexp is used so that denormal numbers diff --git a/sysdeps/ieee754/ldbl-128ibm/e_log2l.c b/sysdeps/ieee754/ldbl-128ibm/e_log2l.c index 323ded0c0f..442ad97254 100644 --- a/sysdeps/ieee754/ldbl-128ibm/e_log2l.c +++ b/sysdeps/ieee754/ldbl-128ibm/e_log2l.c @@ -190,6 +190,9 @@ __ieee754_log2l (x) if (hx >= 0x7ff0000000000000LL) return (x + x); + if (x == 1.0L) + return 0.0L; + /* separate mantissa from exponent */ /* Note, frexp is used so that denormal numbers diff --git a/sysdeps/x86_64/fpu/e_log2l.S b/sysdeps/x86_64/fpu/e_log2l.S index 956489fc3e..c12906d456 100644 --- a/sysdeps/x86_64/fpu/e_log2l.S +++ b/sysdeps/x86_64/fpu/e_log2l.S @@ -45,7 +45,13 @@ ENTRY(__ieee754_log2l) fnstsw // x-1 : x : 1 andb $0x45, %ah jz 2f - fstp %st(1) // x-1 : 1 + fxam + fnstsw + andb $0x45, %ah + cmpb $0x40, %ah + jne 5f + fabs // log2(1) is +0 in all rounding modes. +5: fstp %st(1) // x-1 : 1 fyl2xp1 // log(x) ret diff --git a/sysdeps/x86_64/fpu/libm-test-ulps b/sysdeps/x86_64/fpu/libm-test-ulps index bb549d2b0d..92fef5a134 100644 --- a/sysdeps/x86_64/fpu/libm-test-ulps +++ b/sysdeps/x86_64/fpu/libm-test-ulps @@ -1665,6 +1665,28 @@ ifloat: 1 ildouble: 1 ldouble: 1 +Function: "log2_downward": +double: 2 +float: 2 +idouble: 2 +ifloat: 2 + +Function: "log2_towardzero": +double: 1 +float: 1 +idouble: 1 +ifloat: 1 +ildouble: 1 +ldouble: 1 + +Function: "log2_upward": +double: 2 +float: 2 +idouble: 2 +ifloat: 2 +ildouble: 1 +ldouble: 1 + Function: "log_downward": float: 1 ifloat: 1