Fix for logb/logbf/logbl (bugs 13954/13955/13956)
authorAdhemerval Zanella <azanella@linux.vnet.ibm.com>
Thu, 10 May 2012 20:11:55 +0000 (15:11 -0500)
committerRyan S. Arnold <rsa@linux.vnet.ibm.com>
Thu, 10 May 2012 20:11:55 +0000 (15:11 -0500)
POSIX 2008 states that if the input for 'logb[f|l]' is a subnormal number
it should be treated as if it were normalized.  This means the
implementation should calculate the log2 of the mantissa and add it to the
subnormal exponent (-126 for float and -1022 for double and IBM long
double).  This patch takes care of that.

ChangeLog
NEWS
math/libm-test.inc
sysdeps/ieee754/dbl-64/s_logb.c
sysdeps/ieee754/dbl-64/wordsize-64/s_logb.c
sysdeps/ieee754/flt-32/s_logbf.c
sysdeps/ieee754/ldbl-128/s_logbl.c
sysdeps/ieee754/ldbl-128ibm/s_logbl.c
sysdeps/ieee754/ldbl-96/s_logbl.c

index 8bceaab8be6c9d79f957018824f6dedcb9438285..6848fb4838cbe3995de65415fd3029264a34e3ca 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2012-05-09  Adhemerval Zanella  <azanella@linux.vnet.ibm.com>
+
+       [BZ #13954]
+       [BZ #13955]
+       [BZ #13956]
+       * sysdeps/ieee754/dbl-64/s_logb.c (__logb): Fix for subnormal number.
+       * sysdeps/ieee754/dbl-64/wordsize-64/s_logb.c (__logb): Likewise.
+       * sysdeps/ieee754/flt-32/s_logbf.c (__logf): Likewise.
+       * sysdeps/ieee754/ldbl-128/s_logbl.c (__logbl): Likewise.
+       * sysdeps/ieee754/ldbl-128ibm/s_logbl.c (__logbl): Likewise.
+       * sysdeps/ieee754/ldbl-96/s_logbl.c (__logbl): Likewise.
+       * math/libm-test.inc (logb_test) : Additional logb tests.
+
 2012-05-09  Andreas Schwab  <schwab@linux-m68k.org>
            Andreas Jaeger  <aj@suse.de>
 
diff --git a/NEWS b/NEWS
index 5c90f3da2819a4937f4c920241bb2da3cbfdde7c..b3a12334827af993f752032a040917889513936a 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -23,8 +23,9 @@ Version 2.16
   13852, 13854, 13871, 13872, 13873, 13879, 13883, 13884, 13885, 13886,
   13892, 13895, 13908, 13910, 13911, 13912, 13913, 13914, 13915, 13916,
   13917, 13918, 13919, 13920, 13921, 13922, 13923, 13924, 13926, 13927,
-  13928, 13938, 13941, 13942, 13963, 13967, 13970, 13973, 13979, 13983,
-  14027, 14033, 14034, 14040, 14049, 14053, 14055, 14064, 14080, 14083
+  13928, 13938, 13941, 13942, 13954, 13955, 13956, 13963, 13967, 13970,
+  13973, 13979, 13983, 14027, 14033, 14034, 14040, 14049, 14053, 14055,
+  14064, 14080, 14083
 
 * ISO C11 support:
 
index 542131dc7b16b2eff0345ae20de6c09a92e65553..5a38dbf3a7f9b23ab5215e6ce75d6a11ffae9045 100644 (file)
@@ -5376,6 +5376,22 @@ logb_test (void)
   TEST_f_f (logb, 1024, 10);
   TEST_f_f (logb, -2000, 10);
 
+  TEST_f_f (logb, 0x0.1p-127, -131);
+  TEST_f_f (logb, 0x0.01p-127, -135);
+  TEST_f_f (logb, 0x0.011p-127, -135);
+#ifndef TEST_FLOAT
+  TEST_f_f (logb, 0x0.8p-1022, -1023);
+  TEST_f_f (logb, 0x0.1p-1022, -1026);
+  TEST_f_f (logb, 0x0.00111p-1022, -1034);
+  TEST_f_f (logb, 0x0.00001p-1022, -1042);
+  TEST_f_f (logb, 0x0.000011p-1022, -1042);
+  TEST_f_f (logb, 0x0.0000000000001p-1022, -1074);
+#endif
+#if defined TEST_LDOUBLE && LDBL_MIN_EXP - LDBL_MANT_DIG <= -16400
+  TEST_f_f (logb, 0x1p-16400L, -16400);
+  TEST_f_f (logb, 0x.00000000001p-16382L, -16426);
+#endif
+
   END (logb);
 }
 
index 2382fbb4145b4c21878632dbf9ef6c75471e3335..baa35e14d85dc6733e03e3fd26dc25e4c6677d23 100644 (file)
  * ====================================================
  */
 
-#if defined(LIBM_SCCS) && !defined(lint)
-static char rcsid[] = "$NetBSD: s_logb.c,v 1.8 1995/05/10 20:47:50 jtc Exp $";
-#endif
-
 /*
  * double logb(x)
  * IEEE 754 logb. Included to pass IEEE test suite. Not recommend.
@@ -23,20 +19,29 @@ static char rcsid[] = "$NetBSD: s_logb.c,v 1.8 1995/05/10 20:47:50 jtc Exp $";
 #include <math.h>
 #include <math_private.h>
 
-double __logb(double x)
+double
+__logb (double x)
 {
-       int32_t lx,ix;
-       EXTRACT_WORDS(ix,lx,x);
-       ix &= 0x7fffffff;                       /* high |x| */
-       if((ix|lx)==0) return -1.0/fabs(x);
-       if(ix>=0x7ff00000) return x*x;
-       if((ix>>=20)==0)                        /* IEEE 754 logb */
-               return -1022.0;
-       else
-               return (double) (ix-1023);
+  int32_t lx, ix, rix;
+
+  EXTRACT_WORDS (ix, lx, x);
+  ix &= 0x7fffffff;            /* high |x| */
+  if ((ix | lx) == 0)
+    return -1.0 / fabs (x);
+  if (ix >= 0x7ff00000)
+    return x * x;
+  if (__builtin_expect ((rix = ix >> 20) == 0, 0))
+    {
+      /* POSIX specifies that denormal number is treated as
+         though it were normalized.  */
+      int m1 = (ix == 0) ? 0 : __builtin_clz (ix);
+      int m2 = (lx == 0) ? 0 : __builtin_clz (lx);
+      int ma = (m1 == 0) ? m2 + 32 : m1;
+      return -1022.0 + (double)(11 - ma);
+    }
+  return (double) (rix - 1023);
 }
 weak_alias (__logb, logb)
 #ifdef NO_LONG_DOUBLE
-strong_alias (__logb, __logbl)
-weak_alias (__logb, logbl)
+strong_alias (__logb, __logbl) weak_alias (__logb, logbl)
 #endif
index 2ad6c7ddbda3752e5006bc92bcacde007dca2447..474eeef36b4120f6e663aeff74fd00a7ba01aaa6 100644 (file)
@@ -1,5 +1,5 @@
 /* Compute radix independent exponent.
-   Copyright (C) 2011 Free Software Foundation, Inc.
+   Copyright (C) 2011, 2012 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
 
 double
 __logb (double x)
 {
-  int64_t ix;
+  int64_t ix, ex;
 
   EXTRACT_WORDS64 (ix, x);
   ix &= UINT64_C(0x7fffffffffffffff);
   if (ix == 0)
     return -1.0 / fabs (x);
-  unsigned int ex = ix >> 52;
+  ex = ix >> 52;
   if (ex == 0x7ff)
     return x * x;
-  return ex == 0 ? -1022.0 : (double) (ex - 1023);
+  if (__builtin_expect (ex == 0, 0))
+    {
+      int m = (ix == 0) ? 0 : __builtin_clzl (ix);
+      return -1022.0 + (double)(11 -m);
+    }
+  return (double) (ex - 1023);
 }
 weak_alias (__logb, logb)
 #ifdef NO_LONG_DOUBLE
index b6aa0f057db9165fbf979872257822bfc1e4b39b..025c70de7ecf53dc860b37d0ccff7239bba56831 100644 (file)
  * ====================================================
  */
 
-#if defined(LIBM_SCCS) && !defined(lint)
-static char rcsid[] = "$NetBSD: s_logbf.c,v 1.4 1995/05/10 20:47:51 jtc Exp $";
-#endif
-
 #include <math.h>
 #include <math_private.h>
 
-float __logbf(float x)
+float
+__logbf (float x)
 {
-       int32_t ix;
-       GET_FLOAT_WORD(ix,x);
-       ix &= 0x7fffffff;                       /* high |x| */
-       if(ix==0) return (float)-1.0/fabsf(x);
-       if(ix>=0x7f800000) return x*x;
-       if((ix>>=23)==0)                        /* IEEE 754 logb */
-               return -126.0; 
-       else
-               return (float) (ix-127); 
+  int32_t ix, rix;
+
+  GET_FLOAT_WORD (ix, x);
+  ix &= 0x7fffffff;            /* high |x| */
+  if (ix == 0)
+    return (float) -1.0 / fabsf (x);
+  if (ix >= 0x7f800000)
+    return x * x;
+  if (__builtin_expect ((rix = ix >> 23) == 0, 0))
+    {
+      /* POSIX specifies that denormal number is treated as
+         though it were normalized.  */
+      int m = (ix == 0) ? 0 : __builtin_clz (ix);
+      return -126.0 + (float)(8 - m);
+    }
+  return (float) (rix - 127);
 }
 weak_alias (__logbf, logbf)
index 0b09b289c2e4000c9a10fadac10f960339c62758..cf6003e055ad9ce669bc0a7ba658b86080baa30f 100644 (file)
@@ -26,16 +26,27 @@ static char rcsid[] = "$NetBSD: $";
 #include <math.h>
 #include <math_private.h>
 
-long double __logbl(long double x)
+long double
+__logbl (long double x)
 {
-       int64_t lx,hx;
-       GET_LDOUBLE_WORDS64(hx,lx,x);
-       hx &= 0x7fffffffffffffffLL;             /* high |x| */
-       if((hx|lx)==0) return -1.0/fabs(x);
-       if(hx>=0x7fff000000000000LL) return x*x;
-       if((hx>>=48)==0)                        /* IEEE 754 logb */
-               return -16382.0;
-       else
-               return (long double) (hx-0x3fff);
+  int64_t lx, hx, ex;
+
+  GET_LDOUBLE_WORDS64 (hx, lx, x);
+  hx &= 0x7fffffffffffffffLL;  /* high |x| */
+  if ((hx | lx) == 0)
+    return -1.0 / fabs (x);
+  if (hx >= 0x7fff000000000000LL)
+    return x * x;
+  if ((ex = hx >> 48) == 0)    /* IEEE 754 logb */
+    {
+      /* POSIX specifies that denormal number is treated as
+         though it were normalized.  */
+      int m1 = (hx == 0) ? 0 : __builtin_clzll (hx);
+      int m2 = (lx == 0) ? 0 : __builtin_clzll (lx);
+      int ma = (m1 == 0) ? m2 + 64 : m1;
+      return -16382.0 + (long double)(15 - ma);
+    }
+  return (long double) (ex - 16383);
 }
+
 weak_alias (__logbl, logbl)
index f38b129971098d9f1008bec273bf917b54cc5425..678b6cad57cbaa0b9292fcbaaaf9d1d64ee6eb07 100644 (file)
  * ====================================================
  */
 
-#if defined(LIBM_SCCS) && !defined(lint)
-static char rcsid[] = "$NetBSD: $";
-#endif
-
 /*
  * long double logbl(x)
  * IEEE 754 logb. Included to pass IEEE test suite. Not recommend.
@@ -27,16 +23,27 @@ static char rcsid[] = "$NetBSD: $";
 #include <math_private.h>
 #include <math_ldbl_opt.h>
 
-long double __logbl(long double x)
+long double
+__logbl (long double x)
 {
-       int64_t lx,hx;
-       GET_LDOUBLE_WORDS64(hx,lx,x);
-       hx &= 0x7fffffffffffffffLL;             /* high |x| */
-       if((hx|(lx&0x7fffffffffffffffLL))==0) return -1.0/fabs(x);
-       if(hx>=0x7ff0000000000000LL) return x*x;
-       if((hx>>=52)==0)                        /* IEEE 754 logb */
-               return -1022.0;
-       else
-               return (long double) (hx-0x3ff);
+  int64_t lx, hx, rhx;
+
+  GET_LDOUBLE_WORDS64 (hx, lx, x);
+  hx &= 0x7fffffffffffffffLL;  /* high |x| */
+  if ((hx | (lx & 0x7fffffffffffffffLL)) == 0)
+    return -1.0 / fabs (x);
+  if (hx >= 0x7ff0000000000000LL)
+    return x * x;
+  if (__builtin_expect ((rhx = hx >> 52) == 0, 0))
+    {
+      /* POSIX specifies that denormal number is treated as
+         though it were normalized.  */
+      int m1 = (hx == 0) ? 0 : __builtin_clzll (hx);
+      int m2 = (lx == 0) ? 0 : __builtin_clzll (lx);
+      int ma = (m1 == 0) ? m2 + 64 : m1;
+      return -1022.0 + (long double)(11 - ma);
+    }
+  return (long double) (rhx - 1023);
 }
+
 long_double_symbol (libm, __logbl, logbl);
index 95b644c030f876d287fda059a494e4a1062eadc6..d8ad4bcfcf978a86049d9cf6564f9f7afd50aa58 100644 (file)
  * ====================================================
  */
 
-#if defined(LIBM_SCCS) && !defined(lint)
-static char rcsid[] = "$NetBSD: $";
-#endif
-
 /*
  * long double logbl(x)
  * IEEE 754 logb. Included to pass IEEE test suite. Not recommend.
@@ -27,16 +23,27 @@ static char rcsid[] = "$NetBSD: $";
 #include <math.h>
 #include <math_private.h>
 
-long double __logbl(long double x)
+long double
+__logbl (long double x)
 {
-       int32_t es,lx,ix;
-       GET_LDOUBLE_WORDS(es,ix,lx,x);
-       es &= 0x7fff;                           /* exponent */
-       if((es|ix|lx)==0) return -1.0/fabs(x);
-       if(es==0x7fff) return x*x;
-       if(es==0)                       /* IEEE 754 logb */
-               return -16382.0;
-       else
-               return (long double) (es-0x3fff);
+  int32_t es, lx, ix;
+
+  GET_LDOUBLE_WORDS (es, ix, lx, x);
+  es &= 0x7fff;                        /* exponent */
+  if ((es | ix | lx) == 0)
+    return -1.0 / fabs (x);
+  if (es == 0x7fff)
+    return x * x;
+  if (es == 0)                 /* IEEE 754 logb */
+    {
+      /* POSIX specifies that denormal number is treated as
+         though it were normalized.  */
+      int m1 = (ix == 0) ? 0 : __builtin_clz (ix);
+      int m2 = (lx == 0) ? 0 : __builtin_clz (lx);
+      int ma = (m1 == 0) ? m2 + 32 : m1;
+      return -16382.0 - (long double)(ma);
+    }
+  return (long double) (es - 16383);
 }
+
 weak_alias (__logbl, logbl)