math: Set errno to ERANGE for logb (+-0) [BZ #6793]

logb (+-0) is a pole error: it returns -Inf and raises the
divide-by-zero exception, but it never set errno, even though glibc
defines math_errhandling to include MATH_ERRNO.

Set errno in the zero branch that already exists in every logb
implementation, instead of adding a w_logb wrapper; the
USE_LOGB*_BUILTIN paths have no such branch, so add one there.  The
double and float versions use __math_divzero and __math_divzerof.
There is no long double equivalent, so those keep the explicit
division and use math_opt_barrier to stop the compiler from folding
it away.

The i386 fxtract implementations of logb and logbf cannot set errno,
and adding the error handling to the assembly is not worthwhile, so
they are removed in favour of the generic C ones.  s_logbl.c moves to
sysdeps/x86/fpu, replacing the x86_64 copy that only included it.

The manual described logb (0) as returning +Inf without signalling,
which was wrong in both respects.

Tested on x86_64-linux-gnu.

Signed-off-by: Shamil Abdulaev <ashamil435@gmail.com>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
This commit is contained in:
Shamil Abdulaev
2026-09-07 11:38:48 -03:00
committed by Adhemerval Zanella
parent 9ef758c501
commit 9e1a0b152b
14 changed files with 74 additions and 49 deletions
+2 -1
View File
@@ -669,7 +669,8 @@ due to intermediate rounding.
If @var{x} is de-normalized, @code{logb} returns the exponent @var{x} If @var{x} is de-normalized, @code{logb} returns the exponent @var{x}
would have if it were normalized. If @var{x} is infinity (positive or would have if it were normalized. If @var{x} is infinity (positive or
negative), @code{logb} returns @math{@infinity{}}. If @var{x} is zero, negative), @code{logb} returns @math{@infinity{}}. If @var{x} is zero,
@code{logb} returns @math{@infinity{}}. It does not signal. a pole error occurs: @code{logb} raises the divide-by-zero exception,
sets @code{errno} to @code{ERANGE} and returns @math{-@infinity{}}.
@end deftypefun @end deftypefun
@deftypefun int ilogb (double @var{x}) @deftypefun int ilogb (double @var{x})
+2 -4
View File
@@ -23,10 +23,8 @@ static const struct test_f_f_data logb_test_data[] =
TEST_f_f (logb, plus_infty, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_f_f (logb, plus_infty, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_f_f (logb, minus_infty, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_f_f (logb, minus_infty, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
/* Bug 6793: errno setting may be missing. */ TEST_f_f (logb, 0, minus_infty, NO_INEXACT_EXCEPTION|DIVIDE_BY_ZERO_EXCEPTION|ERRNO_ERANGE),
TEST_f_f (logb, 0, minus_infty, NO_INEXACT_EXCEPTION|DIVIDE_BY_ZERO_EXCEPTION), TEST_f_f (logb, minus_zero, minus_infty, NO_INEXACT_EXCEPTION|DIVIDE_BY_ZERO_EXCEPTION|ERRNO_ERANGE),
TEST_f_f (logb, minus_zero, minus_infty, NO_INEXACT_EXCEPTION|DIVIDE_BY_ZERO_EXCEPTION),
TEST_f_f (logb, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_f_f (logb, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_f_f (logb, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_f_f (logb, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_f_f (logb, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), TEST_f_f (logb, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
-16
View File
@@ -1,16 +0,0 @@
/*
* Public domain.
*/
#include <machine/asm.h>
#include <libm-alias-double.h>
RCSID("$NetBSD: s_logb.S,v 1.4 1995/05/09 00:14:30 jtc Exp $")
ENTRY(__logb)
fldl 4(%esp)
fxtract
fstp %st
ret
END (__logb)
libm_alias_double (__logb, logb)
-16
View File
@@ -1,16 +0,0 @@
/*
* Public domain.
*/
#include <machine/asm.h>
#include <libm-alias-float.h>
RCSID("$NetBSD: s_logbf.S,v 1.3 1995/05/09 00:15:12 jtc Exp $")
ENTRY(__logbf)
flds 4(%esp)
fxtract
fstp %st
ret
END (__logbf)
libm_alias_float (__logb, logb)
+6 -1
View File
@@ -20,11 +20,15 @@
#include <math_private.h> #include <math_private.h>
#include <libm-alias-double.h> #include <libm-alias-double.h>
#include <fix-int-fp-convert-zero.h> #include <fix-int-fp-convert-zero.h>
#include "math_config.h"
double double
__logb (double x) __logb (double x)
{ {
#if USE_LOGB_BUILTIN #if USE_LOGB_BUILTIN
if (__glibc_unlikely (x == 0))
/* Pole error: logb (+-0). */
return __math_divzero (1);
return __builtin_logb (x); return __builtin_logb (x);
#else #else
int64_t ix, ex; int64_t ix, ex;
@@ -32,7 +36,8 @@ __logb (double x)
EXTRACT_WORDS64 (ix, x); EXTRACT_WORDS64 (ix, x);
ix &= UINT64_C(0x7fffffffffffffff); ix &= UINT64_C(0x7fffffffffffffff);
if (ix == 0) if (ix == 0)
return -1.0 / fabs (x); /* Pole error: logb (+-0). */
return __math_divzero (1);
ex = ix >> 52; ex = ix >> 52;
if (ex == 0x7ff) if (ex == 0x7ff)
return x * x; return x * x;
+6 -1
View File
@@ -16,11 +16,15 @@
#include <math_private.h> #include <math_private.h>
#include <libm-alias-float.h> #include <libm-alias-float.h>
#include <fix-int-fp-convert-zero.h> #include <fix-int-fp-convert-zero.h>
#include "math_config.h"
float float
__logbf (float x) __logbf (float x)
{ {
#if USE_LOGBF_BUILTIN #if USE_LOGBF_BUILTIN
if (__glibc_unlikely (x == 0))
/* Pole error: logbf (+-0). */
return __math_divzerof (1);
return __builtin_logbf (x); return __builtin_logbf (x);
#else #else
int32_t ix, rix; int32_t ix, rix;
@@ -28,7 +32,8 @@ __logbf (float x)
GET_FLOAT_WORD (ix, x); GET_FLOAT_WORD (ix, x);
ix &= 0x7fffffff; /* high |x| */ ix &= 0x7fffffff; /* high |x| */
if (ix == 0) if (ix == 0)
return (float) -1.0 / fabsf (x); /* Pole error: logbf (+-0). */
return __math_divzerof (1);
if (ix >= 0x7f800000) if (ix >= 0x7f800000)
return x * x; return x * x;
if (__glibc_unlikely ((rix = ix >> 23) == 0)) if (__glibc_unlikely ((rix = ix >> 23) == 0))
+13 -1
View File
@@ -23,6 +23,8 @@ static char rcsid[] = "$NetBSD: $";
*/ */
#include <math.h> #include <math.h>
#include <errno.h>
#include <math-barriers.h>
#include <math_private.h> #include <math_private.h>
#include <libm-alias-ldouble.h> #include <libm-alias-ldouble.h>
@@ -30,6 +32,12 @@ _Float128
__logbl (_Float128 x) __logbl (_Float128 x)
{ {
#if USE_LOGBL_BUILTIN #if USE_LOGBL_BUILTIN
if (__glibc_unlikely (x == 0))
{
/* Pole error: logbl (+-0). */
__set_errno (ERANGE);
return math_opt_barrier (-1.0) / fabsl (x);
}
return __builtin_logbl (x); return __builtin_logbl (x);
#else #else
/* Use generic implementation. */ /* Use generic implementation. */
@@ -38,7 +46,11 @@ __logbl (_Float128 x)
GET_LDOUBLE_WORDS64 (hx, lx, x); GET_LDOUBLE_WORDS64 (hx, lx, x);
hx &= 0x7fffffffffffffffLL; /* high |x| */ hx &= 0x7fffffffffffffffLL; /* high |x| */
if ((hx | lx) == 0) if ((hx | lx) == 0)
return -1.0 / fabsl (x); {
/* Pole error: logbl (+-0). */
__set_errno (ERANGE);
return math_opt_barrier (-1.0) / fabsl (x);
}
if (hx >= 0x7fff000000000000LL) if (hx >= 0x7fff000000000000LL)
return x * x; return x * x;
if ((ex = hx >> 48) == 0) /* IEEE 754 logb */ if ((ex = hx >> 48) == 0) /* IEEE 754 logb */
+7 -1
View File
@@ -19,6 +19,8 @@
*/ */
#include <math.h> #include <math.h>
#include <errno.h>
#include <math-barriers.h>
#include <math_private.h> #include <math_private.h>
#include <math_ldbl_opt.h> #include <math_ldbl_opt.h>
#include <fix-int-fp-convert-zero.h> #include <fix-int-fp-convert-zero.h>
@@ -34,7 +36,11 @@ __logbl (long double x)
hxs = hx; hxs = hx;
hx &= 0x7fffffffffffffffLL; /* high |x| */ hx &= 0x7fffffffffffffffLL; /* high |x| */
if (hx == 0) if (hx == 0)
return -1.0 / fabs (x); {
/* Pole error: logbl (+-0). */
__set_errno (ERANGE);
return math_opt_barrier (-1.0) / fabs (x);
}
if (hx >= 0x7ff0000000000000LL) if (hx >= 0x7ff0000000000000LL)
return x * x; return x * x;
if (__glibc_unlikely ((rhx = hx >> 52) == 0)) if (__glibc_unlikely ((rhx = hx >> 52) == 0))
+7 -1
View File
@@ -19,6 +19,8 @@
*/ */
#include <math.h> #include <math.h>
#include <errno.h>
#include <math-barriers.h>
#include <math_private.h> #include <math_private.h>
long double long double
@@ -29,7 +31,11 @@ __logbl (long double x)
GET_LDOUBLE_WORDS (es, ix, lx, x); GET_LDOUBLE_WORDS (es, ix, lx, x);
es &= 0x7fff; /* exponent */ es &= 0x7fff; /* exponent */
if ((es | ix | lx) == 0) if ((es | ix | lx) == 0)
return -1.0 / fabsl (x); {
/* Pole error: logbl (+-0). */
__set_errno (ERANGE);
return math_opt_barrier (-1.0) / fabsl (x);
}
if (es == 0x7fff) if (es == 0x7fff)
return x * x; return x * x;
if (es == 0) /* IEEE 754 logb */ if (es == 0) /* IEEE 754 logb */
+7 -2
View File
@@ -22,6 +22,8 @@
# include <sysdeps/ieee754/dbl-64/s_logb.c> # include <sysdeps/ieee754/dbl-64/s_logb.c>
#else #else
# include <math.h> # include <math.h>
# include <errno.h>
# include <math-barriers.h>
# include <math_private.h> # include <math_private.h>
# include <math_ldbl_opt.h> # include <math_ldbl_opt.h>
# include <libm-alias-double.h> # include <libm-alias-double.h>
@@ -34,8 +36,11 @@ __logb (double x)
double ret; double ret;
if (__glibc_unlikely (x == 0.0)) if (__glibc_unlikely (x == 0.0))
/* Raise FE_DIVBYZERO and return -HUGE_VAL[LF]. */ {
return -1.0 / fabs (x); /* Pole error: raise FE_DIVBYZERO, set errno and return -HUGE_VAL. */
__set_errno (ERANGE);
return math_opt_barrier (-1.0) / fabs (x);
}
/* Mask to extract the exponent. */ /* Mask to extract the exponent. */
asm ("xxland %x0,%x1,%x2\n" asm ("xxland %x0,%x1,%x2\n"
+7 -2
View File
@@ -22,6 +22,8 @@
# include <sysdeps/ieee754/flt-32/s_logbf.c> # include <sysdeps/ieee754/flt-32/s_logbf.c>
#else #else
# include <math.h> # include <math.h>
# include <errno.h>
# include <math-barriers.h>
# include <libm-alias-float.h> # include <libm-alias-float.h>
/* This implementation avoids FP to INT conversions by using VSX /* This implementation avoids FP to INT conversions by using VSX
bitwise instructions over FP values. */ bitwise instructions over FP values. */
@@ -32,8 +34,11 @@ __logbf (float x)
double ret; double ret;
if (__glibc_unlikely (x == 0.0)) if (__glibc_unlikely (x == 0.0))
/* Raise FE_DIVBYZERO and return -HUGE_VAL[LF]. */ {
return -1.0 / fabs (x); /* Pole error: raise FE_DIVBYZERO, set errno and return -HUGE_VALF. */
__set_errno (ERANGE);
return math_opt_barrier (-1.0) / fabs (x);
}
/* mask to extract the exponent. */ /* mask to extract the exponent. */
asm ("xxland %x0,%x1,%x2\n" asm ("xxland %x0,%x1,%x2\n"
+7 -2
View File
@@ -22,6 +22,8 @@
# include <./sysdeps/ieee754/ldbl-128ibm/s_logbl.c> # include <./sysdeps/ieee754/ldbl-128ibm/s_logbl.c>
#else #else
# include <math.h> # include <math.h>
# include <errno.h>
# include <math-barriers.h>
# include <math_private.h> # include <math_private.h>
# include <math_ldbl_opt.h> # include <math_ldbl_opt.h>
@@ -35,8 +37,11 @@ __logbl (long double x)
int64_t hx; int64_t hx;
if (__glibc_unlikely (x == 0.0)) if (__glibc_unlikely (x == 0.0))
/* Raise FE_DIVBYZERO and return -HUGE_VAL[LF]. */ {
return -1.0L / __builtin_fabsl (x); /* Pole error: raise FE_DIVBYZERO, set errno and return -HUGE_VALL. */
__set_errno (ERANGE);
return math_opt_barrier (-1.0L) / __builtin_fabsl (x);
}
ldbl_unpack (x, &xh, &xl); ldbl_unpack (x, &xh, &xl);
EXTRACT_WORDS64 (hx, xh); EXTRACT_WORDS64 (hx, xh);
@@ -2,6 +2,9 @@
* Public domain. * Public domain.
*/ */
#include <math.h>
#include <errno.h>
#include <math-barriers.h>
#include <libm-alias-ldouble.h> #include <libm-alias-ldouble.h>
long double long double
@@ -9,6 +12,13 @@ __logbl (long double x)
{ {
long double res; long double res;
if (__glibc_unlikely (x == 0))
{
/* Pole error: logbl (+-0). */
__set_errno (ERANGE);
return math_opt_barrier (-1.0L) / 0.0L;
}
asm ("fxtract\n" asm ("fxtract\n"
"fstp %%st" : "=t" (res) : "0" (x)); "fstp %%st" : "=t" (res) : "0" (x));
return res; return res;
-1
View File
@@ -1 +0,0 @@
#include <sysdeps/i386/fpu/s_logbl.c>