summaryrefslogtreecommitdiff
path: root/libc/src/math
diff options
context:
space:
mode:
authorwldfngrs <wldfngrs@gmail.com>2025-04-08 14:23:38 +0100
committerGitHub <noreply@github.com>2025-04-08 15:23:38 +0200
commitfdf20941a8f95b26578fbeb579019f74efe45545 (patch)
tree177f7a2cfa0b86f08f507a513eb997316c3c2b1c /libc/src/math
parentdae0ef53a0b99c6c2b74143baee5896e8bc5c8e7 (diff)
[libc][math] Fix signaling NaN handling for math functions. (#133347)
Add tests for signaling NaNs, and fix function behavior for handling signaling NaN input. Fixes https://github.com/llvm/llvm-project/issues/124812
Diffstat (limited to 'libc/src/math')
-rw-r--r--libc/src/math/generic/CMakeLists.txt3
-rw-r--r--libc/src/math/generic/acosf.cpp7
-rw-r--r--libc/src/math/generic/asinf.cpp6
-rw-r--r--libc/src/math/generic/asinhf.cpp8
-rw-r--r--libc/src/math/generic/atan2.cpp6
-rw-r--r--libc/src/math/generic/atan2f.cpp7
-rw-r--r--libc/src/math/generic/atanhf.cpp4
-rw-r--r--libc/src/math/generic/cos.cpp6
-rw-r--r--libc/src/math/generic/cosf.cpp5
-rw-r--r--libc/src/math/generic/cosf16.cpp5
-rw-r--r--libc/src/math/generic/cospif.cpp5
-rw-r--r--libc/src/math/generic/cospif16.cpp4
-rw-r--r--libc/src/math/generic/erff.cpp4
-rw-r--r--libc/src/math/generic/log1p.cpp7
-rw-r--r--libc/src/math/generic/logf.cpp5
-rw-r--r--libc/src/math/generic/pow.cpp5
-rw-r--r--libc/src/math/generic/powf.cpp14
-rw-r--r--libc/src/math/generic/sin.cpp5
-rw-r--r--libc/src/math/generic/sincos.cpp6
-rw-r--r--libc/src/math/generic/sincosf.cpp6
-rw-r--r--libc/src/math/generic/sinf.cpp5
-rw-r--r--libc/src/math/generic/sinf16.cpp5
-rw-r--r--libc/src/math/generic/sinpif.cpp5
-rw-r--r--libc/src/math/generic/sinpif16.cpp4
-rw-r--r--libc/src/math/generic/tan.cpp4
-rw-r--r--libc/src/math/generic/tanf.cpp5
-rw-r--r--libc/src/math/generic/tanf16.cpp4
-rw-r--r--libc/src/math/generic/tanpif16.cpp5
28 files changed, 149 insertions, 6 deletions
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index f7c36aab77b7..adbed5b2de48 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -4169,7 +4169,9 @@ add_entrypoint_object(
atan2f_float.h
DEPENDS
.inv_trigf_utils
+ libc.hdr.fenv_macros
libc.src.__support.FPUtil.double_double
+ libc.src.__support.FPUtil.fenv_impl
libc.src.__support.FPUtil.fp_bits
libc.src.__support.FPUtil.multiply_add
libc.src.__support.FPUtil.nearest_integer
@@ -4187,6 +4189,7 @@ add_entrypoint_object(
DEPENDS
.atan_utils
libc.src.__support.FPUtil.double_double
+ libc.src.__support.FPUtil.fenv_impl
libc.src.__support.FPUtil.fp_bits
libc.src.__support.FPUtil.multiply_add
libc.src.__support.FPUtil.nearest_integer
diff --git a/libc/src/math/generic/acosf.cpp b/libc/src/math/generic/acosf.cpp
index 509a5ebc4973..8dd6de2ce747 100644
--- a/libc/src/math/generic/acosf.cpp
+++ b/libc/src/math/generic/acosf.cpp
@@ -84,10 +84,17 @@ LLVM_LIBC_FUNCTION(float, acosf, (float x)) {
0x1.921fb6p+1f)
: /* x == 1.0f */ 0.0f;
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+
+ // |x| <= +/-inf
if (x_abs <= 0x7f80'0000U) {
fputil::set_errno_if_required(EDOM);
fputil::raise_except_if_required(FE_INVALID);
}
+
return x + FPBits::quiet_nan().get_val();
}
diff --git a/libc/src/math/generic/asinf.cpp b/libc/src/math/generic/asinf.cpp
index da854417e85f..12383bf6daca 100644
--- a/libc/src/math/generic/asinf.cpp
+++ b/libc/src/math/generic/asinf.cpp
@@ -108,10 +108,16 @@ LLVM_LIBC_FUNCTION(float, asinf, (float x)) {
// |x| > 1, return NaNs.
if (LIBC_UNLIKELY(x_abs > 0x3f80'0000U)) {
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+
if (x_abs <= 0x7f80'0000U) {
fputil::set_errno_if_required(EDOM);
fputil::raise_except_if_required(FE_INVALID);
}
+
return FPBits::quiet_nan().get_val();
}
diff --git a/libc/src/math/generic/asinhf.cpp b/libc/src/math/generic/asinhf.cpp
index 37b87a821222..0bb7065eb1cf 100644
--- a/libc/src/math/generic/asinhf.cpp
+++ b/libc/src/math/generic/asinhf.cpp
@@ -61,8 +61,14 @@ LLVM_LIBC_FUNCTION(float, asinhf, (float x)) {
};
if (LIBC_UNLIKELY(x_abs >= 0x4bdd'65a5U)) {
- if (LIBC_UNLIKELY(xbits.is_inf_or_nan()))
+ if (LIBC_UNLIKELY(xbits.is_inf_or_nan())) {
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits_t::quiet_nan().get_val();
+ }
+
return x;
+ }
// Exceptional cases when x > 2^24.
switch (x_abs) {
diff --git a/libc/src/math/generic/atan2.cpp b/libc/src/math/generic/atan2.cpp
index 8adfe3321a9e..aa770de33fb1 100644
--- a/libc/src/math/generic/atan2.cpp
+++ b/libc/src/math/generic/atan2.cpp
@@ -8,6 +8,7 @@
#include "src/math/atan2.h"
#include "atan_utils.h"
+#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/double_double.h"
#include "src/__support/FPUtil/multiply_add.h"
@@ -111,8 +112,11 @@ LLVM_LIBC_FUNCTION(double, atan2, (double y, double x)) {
// Check for exceptional cases, whether inputs are 0, inf, nan, or close to
// overflow, or close to underflow.
if (LIBC_UNLIKELY(max_exp > 0x7ffU - 128U || min_exp < 128U)) {
- if (x_bits.is_nan() || y_bits.is_nan())
+ if (x_bits.is_nan() || y_bits.is_nan()) {
+ if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan())
+ fputil::raise_except_if_required(FE_INVALID);
return FPBits::quiet_nan().get_val();
+ }
unsigned x_except = x == 0.0 ? 0 : (FPBits(x_abs).is_inf() ? 2 : 1);
unsigned y_except = y == 0.0 ? 0 : (FPBits(y_abs).is_inf() ? 2 : 1);
diff --git a/libc/src/math/generic/atan2f.cpp b/libc/src/math/generic/atan2f.cpp
index 726cae9c8462..c04b0eb1cc58 100644
--- a/libc/src/math/generic/atan2f.cpp
+++ b/libc/src/math/generic/atan2f.cpp
@@ -7,7 +7,9 @@
//===----------------------------------------------------------------------===//
#include "src/math/atan2f.h"
+#include "hdr/fenv_macros.h"
#include "inv_trigf_utils.h"
+#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/PolyEval.h"
#include "src/__support/FPUtil/double_double.h"
@@ -264,8 +266,11 @@ LLVM_LIBC_FUNCTION(float, atan2f, (float y, float x)) {
double den_d = static_cast<double>(den_f);
if (LIBC_UNLIKELY(max_abs >= 0x7f80'0000U || num_d == 0.0)) {
- if (x_bits.is_nan() || y_bits.is_nan())
+ if (x_bits.is_nan() || y_bits.is_nan()) {
+ if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan())
+ fputil::raise_except_if_required(FE_INVALID);
return FPBits::quiet_nan().get_val();
+ }
double x_d = static_cast<double>(x);
double y_d = static_cast<double>(y);
size_t x_except = (x_d == 0.0) ? 0 : (x_abs == 0x7f80'0000 ? 2 : 1);
diff --git a/libc/src/math/generic/atanhf.cpp b/libc/src/math/generic/atanhf.cpp
index a2051bd3e3e6..2149314d2f67 100644
--- a/libc/src/math/generic/atanhf.cpp
+++ b/libc/src/math/generic/atanhf.cpp
@@ -24,6 +24,10 @@ LLVM_LIBC_FUNCTION(float, atanhf, (float x)) {
// |x| >= 1.0
if (LIBC_UNLIKELY(x_abs >= 0x3F80'0000U)) {
if (xbits.is_nan()) {
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
return x;
}
// |x| == 1.0
diff --git a/libc/src/math/generic/cos.cpp b/libc/src/math/generic/cos.cpp
index b60082bf9c30..5da0f86812a8 100644
--- a/libc/src/math/generic/cos.cpp
+++ b/libc/src/math/generic/cos.cpp
@@ -65,7 +65,11 @@ LLVM_LIBC_FUNCTION(double, cos, (double x)) {
} else {
// Inf or NaN
if (LIBC_UNLIKELY(x_e > 2 * FPBits::EXP_BIAS)) {
- // sin(+-Inf) = NaN
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+ // cos(+-Inf) = NaN
if (xbits.get_mantissa() == 0) {
fputil::set_errno_if_required(EDOM);
fputil::raise_except_if_required(FE_INVALID);
diff --git a/libc/src/math/generic/cosf.cpp b/libc/src/math/generic/cosf.cpp
index 6ea24f9ccd3f..7cdae0986958 100644
--- a/libc/src/math/generic/cosf.cpp
+++ b/libc/src/math/generic/cosf.cpp
@@ -117,6 +117,11 @@ LLVM_LIBC_FUNCTION(float, cosf, (float x)) {
// x is inf or nan.
if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) {
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+
if (x_abs == 0x7f80'0000U) {
fputil::set_errno_if_required(EDOM);
fputil::raise_except_if_required(FE_INVALID);
diff --git a/libc/src/math/generic/cosf16.cpp b/libc/src/math/generic/cosf16.cpp
index 4d42db981ce7..99bb03eb7142 100644
--- a/libc/src/math/generic/cosf16.cpp
+++ b/libc/src/math/generic/cosf16.cpp
@@ -67,6 +67,11 @@ LLVM_LIBC_FUNCTION(float16, cosf16, (float16 x)) {
// cos(+/-inf) = NaN, and cos(NaN) = NaN
if (xbits.is_inf_or_nan()) {
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+
if (xbits.is_inf()) {
fputil::set_errno_if_required(EDOM);
fputil::raise_except_if_required(FE_INVALID);
diff --git a/libc/src/math/generic/cospif.cpp b/libc/src/math/generic/cospif.cpp
index 29566f4fceac..5b6880f853b2 100644
--- a/libc/src/math/generic/cospif.cpp
+++ b/libc/src/math/generic/cospif.cpp
@@ -66,6 +66,11 @@ LLVM_LIBC_FUNCTION(float, cospif, (float x)) {
// x is inf or nan.
if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) {
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+
if (x_abs == 0x7f80'0000U) {
fputil::set_errno_if_required(EDOM);
fputil::raise_except_if_required(FE_INVALID);
diff --git a/libc/src/math/generic/cospif16.cpp b/libc/src/math/generic/cospif16.cpp
index ee74bdb4a369..9dc25920d5cf 100644
--- a/libc/src/math/generic/cospif16.cpp
+++ b/libc/src/math/generic/cospif16.cpp
@@ -54,6 +54,10 @@ LLVM_LIBC_FUNCTION(float16, cospif16, (float16 x)) {
// Check for NaN or infintiy values
if (LIBC_UNLIKELY(x_abs >= 0x7c00)) {
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
// If value is equal to infinity
if (x_abs == 0x7c00) {
fputil::set_errno_if_required(EDOM);
diff --git a/libc/src/math/generic/erff.cpp b/libc/src/math/generic/erff.cpp
index 016afe4a6814..44607a52a2e5 100644
--- a/libc/src/math/generic/erff.cpp
+++ b/libc/src/math/generic/erff.cpp
@@ -135,6 +135,10 @@ LLVM_LIBC_FUNCTION(float, erff, (float x)) {
int sign = xbits.is_neg() ? 1 : 0;
if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) {
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
return (x_abs > 0x7f80'0000) ? x : ONE[sign];
}
diff --git a/libc/src/math/generic/log1p.cpp b/libc/src/math/generic/log1p.cpp
index 058409fed081..09f465a6ba77 100644
--- a/libc/src/math/generic/log1p.cpp
+++ b/libc/src/math/generic/log1p.cpp
@@ -910,7 +910,12 @@ LLVM_LIBC_FUNCTION(double, log1p, (double x)) {
return FPBits_t::quiet_nan().get_val();
}
// x is +Inf or NaN
- return x;
+ if (xbits.is_inf() && xbits.is_pos())
+ return x;
+
+ if (xbits.is_signaling_nan())
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits_t::quiet_nan().get_val();
}
x_dd.hi = x;
} else {
diff --git a/libc/src/math/generic/logf.cpp b/libc/src/math/generic/logf.cpp
index 032d658a941b..e8d2ba2cfe17 100644
--- a/libc/src/math/generic/logf.cpp
+++ b/libc/src/math/generic/logf.cpp
@@ -132,6 +132,11 @@ LLVM_LIBC_FUNCTION(float, logf, (float x)) {
return FPBits::quiet_nan().get_val();
}
// x is +inf or nan
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+
return x;
}
}
diff --git a/libc/src/math/generic/pow.cpp b/libc/src/math/generic/pow.cpp
index 8a12934f6c4b..43e99a7acf69 100644
--- a/libc/src/math/generic/pow.cpp
+++ b/libc/src/math/generic/pow.cpp
@@ -217,6 +217,11 @@ LLVM_LIBC_FUNCTION(double, pow, (double x, double y)) {
uint64_t sign = 0;
///////// BEGIN - Check exceptional cases ////////////////////////////////////
+ // If x or y is signaling NaN
+ if (x_abs.is_signaling_nan() || y_abs.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
// The double precision number that is closest to 1 is (1 - 2^-53), which has
// log2(1 - 2^-53) ~ -1.715...p-53.
diff --git a/libc/src/math/generic/powf.cpp b/libc/src/math/generic/powf.cpp
index 2d7deca3c77b..dfdfd5d6d576 100644
--- a/libc/src/math/generic/powf.cpp
+++ b/libc/src/math/generic/powf.cpp
@@ -664,6 +664,12 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) {
// |y * log2(x)| = 0 or > 151.
// Hence x^y will either overflow or underflow if x is not zero.
if (LIBC_UNLIKELY((y_abs & 0x0007'ffff) == 0) || (y_abs > 0x4f170000)) {
+ // y is signaling NaN
+ if (xbits.is_signaling_nan() || ybits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FloatBits::quiet_nan().get_val();
+ }
+
// Exceptional exponents.
if (y == 0.0f)
return 1.0f;
@@ -736,8 +742,8 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) {
}
}
if (y_abs > 0x4f17'0000) {
+ // if y is NaN
if (y_abs > 0x7f80'0000) {
- // y is NaN
if (x_u == 0x3f80'0000) { // x = 1.0f
// pow(1, NaN) = 1
return 1.0f;
@@ -759,6 +765,12 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) {
// y is finite and non-zero.
if (LIBC_UNLIKELY(((x_u & 0x801f'ffffU) == 0) || x_u >= 0x7f80'0000U ||
x_u < 0x0080'0000U)) {
+ // if x is signaling NaN
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FloatBits::quiet_nan().get_val();
+ }
+
switch (x_u) {
case 0x3f80'0000: // x = 1.0f
return 1.0f;
diff --git a/libc/src/math/generic/sin.cpp b/libc/src/math/generic/sin.cpp
index ba370d4bea4d..a614427bd7ee 100644
--- a/libc/src/math/generic/sin.cpp
+++ b/libc/src/math/generic/sin.cpp
@@ -77,6 +77,11 @@ LLVM_LIBC_FUNCTION(double, sin, (double x)) {
// Inf or NaN
if (LIBC_UNLIKELY(x_e > 2 * FPBits::EXP_BIAS)) {
// sin(+-Inf) = NaN
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+
if (xbits.get_mantissa() == 0) {
fputil::set_errno_if_required(EDOM);
fputil::raise_except_if_required(FE_INVALID);
diff --git a/libc/src/math/generic/sincos.cpp b/libc/src/math/generic/sincos.cpp
index 0ac2f7f99752..08c8a8298f02 100644
--- a/libc/src/math/generic/sincos.cpp
+++ b/libc/src/math/generic/sincos.cpp
@@ -85,6 +85,12 @@ LLVM_LIBC_FUNCTION(void, sincos, (double x, double *sin_x, double *cos_x)) {
} else {
// Inf or NaN
if (LIBC_UNLIKELY(x_e > 2 * FPBits::EXP_BIAS)) {
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ *sin_x = *cos_x = FPBits::quiet_nan().get_val();
+ return;
+ }
+
// sin(+-Inf) = NaN
if (xbits.get_mantissa() == 0) {
fputil::set_errno_if_required(EDOM);
diff --git a/libc/src/math/generic/sincosf.cpp b/libc/src/math/generic/sincosf.cpp
index 623ef636afb1..9c7bf181e485 100644
--- a/libc/src/math/generic/sincosf.cpp
+++ b/libc/src/math/generic/sincosf.cpp
@@ -145,6 +145,12 @@ LLVM_LIBC_FUNCTION(void, sincosf, (float x, float *sinp, float *cosp)) {
// x is inf or nan.
if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) {
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ *sinp = *cosp = FPBits::quiet_nan().get_val();
+ return;
+ }
+
if (x_abs == 0x7f80'0000U) {
fputil::set_errno_if_required(EDOM);
fputil::raise_except_if_required(FE_INVALID);
diff --git a/libc/src/math/generic/sinf.cpp b/libc/src/math/generic/sinf.cpp
index d27ce843a2c9..38ea56f5f28c 100644
--- a/libc/src/math/generic/sinf.cpp
+++ b/libc/src/math/generic/sinf.cpp
@@ -136,6 +136,11 @@ LLVM_LIBC_FUNCTION(float, sinf, (float x)) {
#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) {
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+
if (x_abs == 0x7f80'0000U) {
fputil::set_errno_if_required(EDOM);
fputil::raise_except_if_required(FE_INVALID);
diff --git a/libc/src/math/generic/sinf16.cpp b/libc/src/math/generic/sinf16.cpp
index 85e55a614588..28debbd52a9a 100644
--- a/libc/src/math/generic/sinf16.cpp
+++ b/libc/src/math/generic/sinf16.cpp
@@ -87,6 +87,11 @@ LLVM_LIBC_FUNCTION(float16, sinf16, (float16 x)) {
}
if (xbits.is_inf_or_nan()) {
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+
if (xbits.is_inf()) {
fputil::set_errno_if_required(EDOM);
fputil::raise_except_if_required(FE_INVALID);
diff --git a/libc/src/math/generic/sinpif.cpp b/libc/src/math/generic/sinpif.cpp
index f572ded06b25..492689d594d9 100644
--- a/libc/src/math/generic/sinpif.cpp
+++ b/libc/src/math/generic/sinpif.cpp
@@ -83,6 +83,11 @@ LLVM_LIBC_FUNCTION(float, sinpif, (float x)) {
// check for NaN values
if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) {
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+
if (x_abs == 0x7f80'0000U) {
fputil::set_errno_if_required(EDOM);
fputil::raise_except_if_required(FE_INVALID);
diff --git a/libc/src/math/generic/sinpif16.cpp b/libc/src/math/generic/sinpif16.cpp
index 51ea595653b4..68af484a6c5d 100644
--- a/libc/src/math/generic/sinpif16.cpp
+++ b/libc/src/math/generic/sinpif16.cpp
@@ -50,6 +50,10 @@ LLVM_LIBC_FUNCTION(float16, sinpif16, (float16 x)) {
if (LIBC_UNLIKELY(x_abs >= 0x6400)) {
// Check for NaN or infinity values
if (LIBC_UNLIKELY(x_abs >= 0x7c00)) {
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
// If value is equal to infinity
if (x_abs == 0x7c00) {
fputil::set_errno_if_required(EDOM);
diff --git a/libc/src/math/generic/tan.cpp b/libc/src/math/generic/tan.cpp
index a899a2128d38..89b812cfc23a 100644
--- a/libc/src/math/generic/tan.cpp
+++ b/libc/src/math/generic/tan.cpp
@@ -163,6 +163,10 @@ LLVM_LIBC_FUNCTION(double, tan, (double x)) {
} else {
// Inf or NaN
if (LIBC_UNLIKELY(x_e > 2 * FPBits::EXP_BIAS)) {
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
// tan(+-Inf) = NaN
if (xbits.get_mantissa() == 0) {
fputil::set_errno_if_required(EDOM);
diff --git a/libc/src/math/generic/tanf.cpp b/libc/src/math/generic/tanf.cpp
index a15aa9796cbd..ca5e35dca4c9 100644
--- a/libc/src/math/generic/tanf.cpp
+++ b/libc/src/math/generic/tanf.cpp
@@ -113,6 +113,11 @@ LLVM_LIBC_FUNCTION(float, tanf, (float x)) {
if (LIBC_UNLIKELY(x_abs > 0x4d56'd354U)) {
// Inf or NaN
if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) {
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+
if (x_abs == 0x7f80'0000U) {
fputil::set_errno_if_required(EDOM);
fputil::raise_except_if_required(FE_INVALID);
diff --git a/libc/src/math/generic/tanf16.cpp b/libc/src/math/generic/tanf16.cpp
index 97d201b65bbe..229f4a363670 100644
--- a/libc/src/math/generic/tanf16.cpp
+++ b/libc/src/math/generic/tanf16.cpp
@@ -84,6 +84,10 @@ LLVM_LIBC_FUNCTION(float16, tanf16, (float16 x)) {
// tan(+/-inf) = NaN, and tan(NaN) = NaN
if (LIBC_UNLIKELY(x_abs >= 0x7c00)) {
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
// x = +/-inf
if (x_abs == 0x7c00) {
fputil::set_errno_if_required(EDOM);
diff --git a/libc/src/math/generic/tanpif16.cpp b/libc/src/math/generic/tanpif16.cpp
index 71cf25c9741a..792d405b1bb9 100644
--- a/libc/src/math/generic/tanpif16.cpp
+++ b/libc/src/math/generic/tanpif16.cpp
@@ -63,6 +63,11 @@ LLVM_LIBC_FUNCTION(float16, tanpif16, (float16 x)) {
if (LIBC_UNLIKELY(x_abs >= 0x6400)) {
// Check for NaN or infinity values
if (LIBC_UNLIKELY(x_abs >= 0x7c00)) {
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+ // is inf
if (x_abs == 0x7c00) {
fputil::set_errno_if_required(EDOM);
fputil::raise_except_if_required(FE_INVALID);