This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] BZ#15235: Fix spurious underlfows for expl ldbm-128ibm


This patch corrects spurious underflow exceptions generated by 
expl(-744.44006192138126231410729844608163411L) for ldbl-128ibm.
The spurious underflow exceptions is generated when the result
is scaled back with subnormal number multiplication. It follows
the dbl-64 implementation by temporary disabling the exception
generation in the scale multiplication.

Any tips, comments, advices?

--

2013-03-06  Adhemerval Zanella  <azanella@linux.vnet.ibm.com>

	[BZ #15235]
	* sysdeps/ieee754/ldbl-128ibm/e_expl.c (__ieee754_expl): Correct spurious
	underflow expcetion.
	* math/libm-test.inc: Add exp test.


diff --git a/NEWS b/NEWS
index 470f513..6c06d3c 100644
--- a/NEWS
+++ b/NEWS
@@ -11,7 +11,7 @@ Version 2.18
 
   11561, 13550, 13889, 13951, 14142, 14200, 14317, 14327, 14496, 14920,
   14964, 14981, 14982, 14985, 14994, 14996, 15003, 15006, 15020, 15023,
-  15036, 15054, 15055, 15062, 15078, 15160, 15232.
+  15036, 15054, 15055, 15062, 15078, 15160, 15232, 15235.
 
 * Add support for calling C++11 thread_local object destructors on thread
   and program exit.  This needs compiler support for offloading C++11
diff --git a/math/libm-test.inc b/math/libm-test.inc
index dd08aff..f7a4bc9 100644
--- a/math/libm-test.inc
+++ b/math/libm-test.inc
@@ -4308,6 +4308,7 @@ exp_test (void)
   TEST_f_f (exp, 0.75L, 2.11700001661267466854536981983709561L);
   TEST_f_f (exp, 50.0L, 5184705528587072464087.45332293348538L);
   TEST_f_f (exp, 88.72269439697265625L, 3.40233126623160774937554134772290447915e38L);
+  TEST_f_f (exp, -744.44006192138126231410729844608163411L, 4.940705865224083212785530537372924157526226e-324L);
   TEST_f_f (exp, 709.75L, 1.739836873264160557698252711673830393864768e+308L);
 #if defined TEST_LDOUBLE && __LDBL_MAX_EXP__ > 1024
   /* The result can only be represented in sane long double.  */
diff --git a/sysdeps/ieee754/ldbl-128ibm/e_expl.c b/sysdeps/ieee754/ldbl-128ibm/e_expl.c
index 9fd6198..a5e04fb 100644
--- a/sysdeps/ieee754/ldbl-128ibm/e_expl.c
+++ b/sysdeps/ieee754/ldbl-128ibm/e_expl.c
@@ -138,14 +138,12 @@ __ieee754_expl (long double x)
   if (isless (x, himark) && isgreater (x, lomark))
     {
       int tval1, tval2, unsafe, n_i, exponent2;
-      long double x22, n, result, xl;
-      union ibm_extended_long_double ex2_u, scale_u;
+      long double x22, n, xl;
+      union ibm_extended_long_double ex2_u, scale_u, result;
       fenv_t oldenv;
 
       feholdexcept (&oldenv);
-#ifdef FE_TONEAREST
       fesetround (FE_TONEAREST);
-#endif
 
       n = __roundl (x*M_1_LN2);
       x = x-n*M_LN2_0;
@@ -166,7 +164,7 @@ __ieee754_expl (long double x)
 		* __expl_table[T_EXPL_RES2 + tval2];
       n_i = (int)n;
       /* 'unsafe' is 1 iff n_1 != 0.  */
-      unsafe = fabsl(n_i) >= -LDBL_MIN_EXP - 1;
+      unsafe = abs(n_i) >= -LDBL_MIN_EXP - 1;
       ex2_u.ieee.exponent += n_i >> unsafe;
       /* Fortunately, there are no subnormal lowpart doubles in
 	 __expl_table, only normal values and zeros.
@@ -204,7 +202,7 @@ __ieee754_expl (long double x)
       /* Return result.  */
       fesetenv (&oldenv);
 
-      result = x22 * ex2_u.d + ex2_u.d;
+      result.d = x22 * ex2_u.d + ex2_u.d;
 
       /* Now we can test whether the result is ultimate or if we are unsure.
 	 In the later case we should probably call a mpn based routine to give
@@ -235,10 +233,22 @@ __ieee754_expl (long double x)
 	    return __ieee754_expl_proc2 (origx);
 	  }
        */
-      if (!unsafe)
-	return result;
-      else
-	return result * scale_u.d;
+      if (unsafe)
+	{
+	  /* The scale with denormal number might generated undeflow for
+	     first high double multiplication. The exception holding is
+	     to avoid it.  */
+	  if (result.ieee.exponent + scale_u.ieee.exponent
+		< IBM_EXTENDED_LONG_DOUBLE_BIAS)
+	    {
+	      feholdexcept (&oldenv);
+	      result.d *= scale_u.d;
+	      fesetenv (&oldenv);
+	    }
+	  else
+	    result.d *= scale_u.d;
+	}
+      return result.d;
     }
   /* Exceptional cases:  */
   else if (isless (x, himark))
-- 
1.7.1


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]