[libc-commits] [libc] [libc][math] Implement double precision tgamma (PR #210970)
Hardik Chona via libc-commits
libc-commits at lists.llvm.org
Wed Jul 22 04:33:34 PDT 2026
https://github.com/un-pixelated updated https://github.com/llvm/llvm-project/pull/210970
>From 136c6a5beb3d03c5a40879ae48c7a1762cdc0e4b Mon Sep 17 00:00:00 2001
From: Hardik Chona <iamhardikchona at gmail.com>
Date: Tue, 21 Jul 2026 15:49:40 +0530
Subject: [PATCH 01/13] [libc][math] scaffolding for tgamma
---
libc/config/linux/x86_64/entrypoints.txt | 1 +
libc/src/__support/math/CMakeLists.txt | 11 ++++++++
libc/src/__support/math/tgamma.h | 33 ++++++++++++++++++++++++
libc/src/math/generic/CMakeLists.txt | 10 +++++++
libc/src/math/generic/tgamma.cpp | 16 ++++++++++++
5 files changed, 71 insertions(+)
create mode 100644 libc/src/__support/math/tgamma.h
create mode 100644 libc/src/math/generic/tgamma.cpp
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 0a4fb747c2940..0d8492cb4df3a 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -926,6 +926,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
libc.src.math.tanf16
libc.src.math.tanhf16
libc.src.math.tanpif16
+ libc.src.math.tgamma
libc.src.math.totalorderf16
libc.src.math.totalordermagf16
libc.src.math.truncf16
diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index 9f4624682eafe..5eaca01a5b096 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -5550,6 +5550,17 @@ add_header_library(
libc.src.__support.macros.optimization
)
+add_header_library(
+ tgamma
+ HDRS
+ tgamma.h
+ DEPENDS
+ libc.src.__support.FPUtil.FEnvImpl
+ libc.src.__support.FPUtil.FPBits
+ libc.src.__support.macros.config
+ libc.src.__support.macros.optimization
+)
+
add_header_library(
totalorder
HDRS
diff --git a/libc/src/__support/math/tgamma.h b/libc/src/__support/math/tgamma.h
new file mode 100644
index 0000000000000..f1db64538c052
--- /dev/null
+++ b/libc/src/__support/math/tgamma.h
@@ -0,0 +1,33 @@
+//===-- Double-precision tgamma function ----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_TGAMMA_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_TGAMMA_H
+
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+namespace math {
+
+LIBC_INLINE double tgamma(double x) {
+ using FPBits = fputil::FPBits<double>;
+ FPBits xbits(x);
+
+ // TODO: implement
+ return 0.0;
+}
+
+} // namespace math
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_TGAMMA_H
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index d5661f6f55e91..84aa3f7356105 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -466,6 +466,16 @@ add_entrypoint_object(
libc.src.__support.math.tanpif16
)
+add_entrypoint_object(
+ tgamma
+ SRCS
+ tgamma.cpp
+ HDRS
+ ../tgamma.h
+ DEPENDS
+ libc.src.__support.math.tgamma
+)
+
add_entrypoint_object(
fabs
SRCS
diff --git a/libc/src/math/generic/tgamma.cpp b/libc/src/math/generic/tgamma.cpp
new file mode 100644
index 0000000000000..55512f4f510da
--- /dev/null
+++ b/libc/src/math/generic/tgamma.cpp
@@ -0,0 +1,16 @@
+//===-- Double precision tgamma function ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/math/tgamma.h"
+#include "src/__support/math/tgamma.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(double, tgamma, (double x)) { return math::tgamma(x); }
+
+} // namespace LIBC_NAMESPACE_DECL
>From b2e54ade53f63f1953fcf797db021fa3b75366e0 Mon Sep 17 00:00:00 2001
From: Hardik Chona <iamhardikchona at gmail.com>
Date: Tue, 21 Jul 2026 15:57:15 +0530
Subject: [PATCH 02/13] [libc][math] add entrypoint for macOS and confirm build
is working
---
libc/config/darwin/aarch64/entrypoints.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/libc/config/darwin/aarch64/entrypoints.txt b/libc/config/darwin/aarch64/entrypoints.txt
index 15adad72ab459..79943f155c8b7 100644
--- a/libc/config/darwin/aarch64/entrypoints.txt
+++ b/libc/config/darwin/aarch64/entrypoints.txt
@@ -391,6 +391,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.tanf
libc.src.math.tanhf
libc.src.math.tanpif
+ libc.src.math.tgamma
libc.src.math.totalorder
libc.src.math.totalorderf
libc.src.math.totalorderl
>From e53630f826223fb91b827450bbfd5c18ae7aeece Mon Sep 17 00:00:00 2001
From: Hardik Chona <iamhardikchona at gmail.com>
Date: Tue, 21 Jul 2026 17:23:22 +0530
Subject: [PATCH 03/13] [libc][math] Write smoke tests for tgamma and wire up
CMakeLists.txt
---
libc/test/src/math/smoke/CMakeLists.txt | 11 ++++++
libc/test/src/math/smoke/tgamma_test.cpp | 49 ++++++++++++++++++++++++
2 files changed, 60 insertions(+)
create mode 100644 libc/test/src/math/smoke/tgamma_test.cpp
diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt
index 81f76fa7681fd..ad1e6a648ed7a 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -180,6 +180,17 @@ add_fp_unittest(
libc.src.math.tanpif16
)
+add_fp_unittest(
+ tgamma_test
+ SUITE
+ libc-math-smoke-tests
+ SRCS
+ tgamma_test.cpp
+ DEPENDS
+ libc.src.math.tgamma
+ libc.hdr.errno_macros
+)
+
add_fp_unittest(
fabs_test
SUITE
diff --git a/libc/test/src/math/smoke/tgamma_test.cpp b/libc/test/src/math/smoke/tgamma_test.cpp
new file mode 100644
index 0000000000000..630237facbfc6
--- /dev/null
+++ b/libc/test/src/math/smoke/tgamma_test.cpp
@@ -0,0 +1,49 @@
+//===-- Unittests for tgamma ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/math/tgamma.h"
+#include "hdr/errno_macros.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+
+using LlvmLibcTgammaTest = LIBC_NAMESPACE::testing::FPTest<double>;
+
+using LIBC_NAMESPACE::testing::tlog;
+
+TEST_F(LlvmLibcTgammaTest, SpecialNumbers) {
+ EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::tgamma(sNaN), FE_INVALID);
+ EXPECT_MATH_ERRNO(0);
+
+ EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::tgamma(neg_inf), FE_INVALID);
+ EXPECT_MATH_ERRNO(EDOM);
+
+ EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::tgamma(-1.0), FE_INVALID);
+ EXPECT_MATH_ERRNO(EDOM);
+
+ EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::tgamma(zero), FE_DIVBYZERO);
+ EXPECT_MATH_ERRNO(ERANGE);
+
+ EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, LIBC_NAMESPACE::tgamma(neg_zero), FE_DIVBYZERO);
+ EXPECT_MATH_ERRNO(ERANGE);
+
+ // Source: https://members.loria.fr/PZimmermann/papers/gamma.pdf
+ // Gamma(0x1.573fae561f648p+7) > DBL_MAX
+ EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::tgamma(0x1.573fae561f648p+7), FE_OVERFLOW);
+ EXPECT_MATH_ERRNO(ERANGE);
+
+ // One ULP below 0x1.573fae561f648p+7
+ // It is the largest input our function returns a finite output for
+ EXPECT_FP_NE(inf, LIBC_NAMESPACE::tgamma(0x1.573fae561f647p+7));
+ EXPECT_MATH_ERRNO(0);
+
+ EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::tgamma(aNaN));
+ EXPECT_FP_EQ_ALL_ROUNDING(inf, LIBC_NAMESPACE::tgamma(inf));
+
+ EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::tgamma(1.0));
+ EXPECT_MATH_ERRNO(0);
+}
>From 3692a6714a521d0b4943d63f607a823c01ae74cc Mon Sep 17 00:00:00 2001
From: Hardik Chona <iamhardikchona at gmail.com>
Date: Tue, 21 Jul 2026 17:25:03 +0530
Subject: [PATCH 04/13] [libc][math] nits fixed
---
libc/test/src/math/smoke/tgamma_test.cpp | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/libc/test/src/math/smoke/tgamma_test.cpp b/libc/test/src/math/smoke/tgamma_test.cpp
index 630237facbfc6..261598b361773 100644
--- a/libc/test/src/math/smoke/tgamma_test.cpp
+++ b/libc/test/src/math/smoke/tgamma_test.cpp
@@ -6,15 +6,13 @@
//
//===----------------------------------------------------------------------===//
-#include "src/math/tgamma.h"
#include "hdr/errno_macros.h"
+#include "src/math/tgamma.h"
#include "test/UnitTest/FPMatcher.h"
#include "test/UnitTest/Test.h"
using LlvmLibcTgammaTest = LIBC_NAMESPACE::testing::FPTest<double>;
-using LIBC_NAMESPACE::testing::tlog;
-
TEST_F(LlvmLibcTgammaTest, SpecialNumbers) {
EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::tgamma(sNaN), FE_INVALID);
EXPECT_MATH_ERRNO(0);
>From fd6202f7eaeaee4899e8a92c3b68bb1ab472c4f3 Mon Sep 17 00:00:00 2001
From: Hardik Chona <iamhardikchona at gmail.com>
Date: Tue, 21 Jul 2026 18:00:19 +0530
Subject: [PATCH 05/13] [libc][math] add to entrypoints for linux arm and linux
aarch64
---
libc/config/linux/aarch64/entrypoints.txt | 1 +
libc/config/linux/arm/entrypoints.txt | 1 +
2 files changed, 2 insertions(+)
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 2e7b9276ab068..d258492d6e4b2 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -711,6 +711,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.tanf
libc.src.math.tanhf
libc.src.math.tanpif
+ libc.src.math.tgamma
libc.src.math.totalorder
libc.src.math.totalorderf
libc.src.math.totalorderl
diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt
index 1986d6a5347dc..539aa64cfb4c1 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -489,6 +489,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.tanf
libc.src.math.tanhf
libc.src.math.tanpif
+ libc.src.math.tgamma
libc.src.math.totalorder
libc.src.math.totalorderf
libc.src.math.totalorderl
>From f1937ef0cf6e051fc65a87abfab638d26b62b053 Mon Sep 17 00:00:00 2001
From: Hardik Chona <iamhardikchona at gmail.com>
Date: Tue, 21 Jul 2026 19:44:13 +0530
Subject: [PATCH 06/13] clang-format
---
libc/test/src/math/smoke/tgamma_test.cpp | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/libc/test/src/math/smoke/tgamma_test.cpp b/libc/test/src/math/smoke/tgamma_test.cpp
index 261598b361773..458aeb6b801b9 100644
--- a/libc/test/src/math/smoke/tgamma_test.cpp
+++ b/libc/test/src/math/smoke/tgamma_test.cpp
@@ -17,7 +17,8 @@ TEST_F(LlvmLibcTgammaTest, SpecialNumbers) {
EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::tgamma(sNaN), FE_INVALID);
EXPECT_MATH_ERRNO(0);
- EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::tgamma(neg_inf), FE_INVALID);
+ EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::tgamma(neg_inf),
+ FE_INVALID);
EXPECT_MATH_ERRNO(EDOM);
EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::tgamma(-1.0), FE_INVALID);
@@ -26,12 +27,14 @@ TEST_F(LlvmLibcTgammaTest, SpecialNumbers) {
EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::tgamma(zero), FE_DIVBYZERO);
EXPECT_MATH_ERRNO(ERANGE);
- EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, LIBC_NAMESPACE::tgamma(neg_zero), FE_DIVBYZERO);
+ EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, LIBC_NAMESPACE::tgamma(neg_zero),
+ FE_DIVBYZERO);
EXPECT_MATH_ERRNO(ERANGE);
-
+
// Source: https://members.loria.fr/PZimmermann/papers/gamma.pdf
// Gamma(0x1.573fae561f648p+7) > DBL_MAX
- EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::tgamma(0x1.573fae561f648p+7), FE_OVERFLOW);
+ EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::tgamma(0x1.573fae561f648p+7),
+ FE_OVERFLOW);
EXPECT_MATH_ERRNO(ERANGE);
// One ULP below 0x1.573fae561f648p+7
>From 5eec2d94fd0c756bdf04e44d9e78c0d8168a7649 Mon Sep 17 00:00:00 2001
From: Hardik Chona <iamhardikchona at gmail.com>
Date: Tue, 21 Jul 2026 22:38:15 +0530
Subject: [PATCH 07/13] [libc][math] Add entry to math.yaml
---
libc/include/math.yaml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/libc/include/math.yaml b/libc/include/math.yaml
index 14e243168ad47..dff840491e3e5 100644
--- a/libc/include/math.yaml
+++ b/libc/include/math.yaml
@@ -2756,6 +2756,12 @@ functions:
arguments:
- type: _Float16
guard: LIBC_TYPES_HAS_FLOAT16
+ - name: tgamma
+ standards:
+ - stdc
+ return_type: double
+ arguments:
+ - type: double
- name: totalorder
standards:
- stdc
>From b653ceb6e0f35e724a1d50534e294a9d915a429f Mon Sep 17 00:00:00 2001
From: Hardik Chona <iamhardikchona at gmail.com>
Date: Tue, 21 Jul 2026 23:03:36 +0530
Subject: [PATCH 08/13] [libc][math] Fixed build errors, removed 1.0 smoke test
(range based, will be added later), and added entrypoints.
---
libc/src/__support/math/CMakeLists.txt | 4 +--
libc/src/__support/math/tgamma.h | 45 +++++++++++++++++++++++-
libc/test/src/math/smoke/tgamma_test.cpp | 5 +--
3 files changed, 47 insertions(+), 7 deletions(-)
diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index 5eaca01a5b096..74e4e20df5d5b 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -5555,8 +5555,8 @@ add_header_library(
HDRS
tgamma.h
DEPENDS
- libc.src.__support.FPUtil.FEnvImpl
- libc.src.__support.FPUtil.FPBits
+ libc.src.__support.FPUtil.fenv_impl
+ libc.src.__support.FPUtil.fp_bits
libc.src.__support.macros.config
libc.src.__support.macros.optimization
)
diff --git a/libc/src/__support/math/tgamma.h b/libc/src/__support/math/tgamma.h
index f1db64538c052..3ca3507e3a52e 100644
--- a/libc/src/__support/math/tgamma.h
+++ b/libc/src/__support/math/tgamma.h
@@ -9,8 +9,11 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_TGAMMA_H
#define LLVM_LIBC_SRC___SUPPORT_MATH_TGAMMA_H
+#include "hdr/errno_macros.h"
+#include "hdr/fenv_macros.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/nearest_integer.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/optimization.h"
@@ -22,7 +25,47 @@ LIBC_INLINE double tgamma(double x) {
using FPBits = fputil::FPBits<double>;
FPBits xbits(x);
- // TODO: implement
+ if (LIBC_UNLIKELY(xbits.is_inf_or_nan())) {
+ if (xbits.is_nan()) {
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+ return x;
+ }
+ // tgamma(-inf) = NaN with domain error
+ if (xbits.is_neg()) {
+ fputil::set_errno_if_required(EDOM);
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+ // tgamma(+inf) = +inf.
+ return x;
+ }
+
+ // Gamma has a pole at 0, with sign following the input
+ if (LIBC_UNLIKELY(x == 0.0)) {
+ fputil::set_errno_if_required(ERANGE);
+ fputil::raise_except_if_required(FE_DIVBYZERO);
+ return FPBits::inf(xbits.sign()).get_val();
+ }
+
+ // tgamma(x) > DBL_MAX for x >= 0x1.573fae561f648p+7
+ // Source: https://members.loria.fr/PZimmermann/papers/gamma.pdf
+ if (LIBC_UNLIKELY(x >= 0x1.573fae561f648p+7)) {
+ fputil::set_errno_if_required(ERANGE);
+ fputil::raise_except_if_required(FE_OVERFLOW);
+ return FPBits::inf().get_val();
+ }
+
+ // Gamma has poles at all negative integers
+ if (LIBC_UNLIKELY(x < 0.0 && fputil::nearest_integer(x) == x)) {
+ fputil::set_errno_if_required(EDOM);
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+
+ // TODO: Implement tgamma for the remaining input ranges
return 0.0;
}
diff --git a/libc/test/src/math/smoke/tgamma_test.cpp b/libc/test/src/math/smoke/tgamma_test.cpp
index 458aeb6b801b9..51e92d6238840 100644
--- a/libc/test/src/math/smoke/tgamma_test.cpp
+++ b/libc/test/src/math/smoke/tgamma_test.cpp
@@ -32,7 +32,7 @@ TEST_F(LlvmLibcTgammaTest, SpecialNumbers) {
EXPECT_MATH_ERRNO(ERANGE);
// Source: https://members.loria.fr/PZimmermann/papers/gamma.pdf
- // Gamma(0x1.573fae561f648p+7) > DBL_MAX
+ // tgamma(0x1.573fae561f648p+7) > DBL_MAX
EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::tgamma(0x1.573fae561f648p+7),
FE_OVERFLOW);
EXPECT_MATH_ERRNO(ERANGE);
@@ -44,7 +44,4 @@ TEST_F(LlvmLibcTgammaTest, SpecialNumbers) {
EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::tgamma(aNaN));
EXPECT_FP_EQ_ALL_ROUNDING(inf, LIBC_NAMESPACE::tgamma(inf));
-
- EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::tgamma(1.0));
- EXPECT_MATH_ERRNO(0);
}
>From 254aca24440fdd3e81df547de691a73b46c36360 Mon Sep 17 00:00:00 2001
From: Hardik Chona <iamhardikchona at gmail.com>
Date: Tue, 21 Jul 2026 23:12:48 +0530
Subject: [PATCH 09/13] [libc][math] nit: comment consistency
---
libc/src/__support/math/tgamma.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libc/src/__support/math/tgamma.h b/libc/src/__support/math/tgamma.h
index 3ca3507e3a52e..975fb881dd2a4 100644
--- a/libc/src/__support/math/tgamma.h
+++ b/libc/src/__support/math/tgamma.h
@@ -39,7 +39,7 @@ LIBC_INLINE double tgamma(double x) {
fputil::raise_except_if_required(FE_INVALID);
return FPBits::quiet_nan().get_val();
}
- // tgamma(+inf) = +inf.
+ // tgamma(+inf) = +inf
return x;
}
>From f2bf229f61d196afb835427e3cdd21376f1f7f66 Mon Sep 17 00:00:00 2001
From: Hardik Chona <iamhardikchona at gmail.com>
Date: Wed, 22 Jul 2026 16:13:28 +0530
Subject: [PATCH 10/13] [libc][math] Add positive integer range
---
libc/src/__support/math/tgamma.h | 102 +++++++++++++++++++++++++++++++
1 file changed, 102 insertions(+)
diff --git a/libc/src/__support/math/tgamma.h b/libc/src/__support/math/tgamma.h
index 975fb881dd2a4..71fa2915b5858 100644
--- a/libc/src/__support/math/tgamma.h
+++ b/libc/src/__support/math/tgamma.h
@@ -65,6 +65,108 @@ LIBC_INLINE double tgamma(double x) {
return FPBits::quiet_nan().get_val();
}
+ // Range 1: x is a positive integer in [1, 171]
+
+ // FACTORIALS[x] = x!, correctly rounded to nearest double
+ // tgamma(x) = FACTORIALS[x - 1]
+ // x = 0..22 exact, x = 23..170 correctly-rounded
+ // 170! is the largest factorial that fits under DBL_MAX
+ // Generated using a simple Sollya for-loop
+ static constexpr double FACTORIALS[171] = {
+ 0x1.0000000000000p+0, 0x1.0000000000000p+0,
+ 0x1.0000000000000p+1, 0x1.8000000000000p+2,
+ 0x1.8000000000000p+4, 0x1.e000000000000p+6,
+ 0x1.6800000000000p+9, 0x1.3b00000000000p+12,
+ 0x1.3b00000000000p+15, 0x1.6260000000000p+18,
+ 0x1.baf8000000000p+21, 0x1.308a800000000p+25,
+ 0x1.c8cfc00000000p+28, 0x1.7328cc0000000p+32,
+ 0x1.44c3b28000000p+36, 0x1.3077775800000p+40,
+ 0x1.3077775800000p+44, 0x1.437eeecd80000p+48,
+ 0x1.6beecca730000p+52, 0x1.b02b930689000p+56,
+ 0x1.0e1b3be415a00p+61, 0x1.6283be9b5c620p+65,
+ 0x1.e77526159f06cp+69, 0x1.5e5c335f8a4cep+74,
+ 0x1.06c52687a7b9ap+79, 0x1.9a940c33f6121p+83,
+ 0x1.4d9849ea37eebp+88, 0x1.19787e5d9f316p+93,
+ 0x1.ec92dd23d6967p+97, 0x1.be6518687a785p+102,
+ 0x1.a27ec6e1f2d0dp+107, 0x1.956ad0aae33a4p+112,
+ 0x1.956ad0aae33a4p+117, 0x1.a21627303a541p+122,
+ 0x1.bc3789a33df96p+127, 0x1.e5dcbe8a8bc8cp+132,
+ 0x1.114c2b2deea0fp+138, 0x1.3c0011ed1bea1p+143,
+ 0x1.774015499125fp+148, 0x1.c95619f1a8e64p+153,
+ 0x1.1dd5d037098fep+159, 0x1.6e39f2c684406p+164,
+ 0x1.e0ac0ea48d948p+169, 0x1.42f399d68f1fcp+175,
+ 0x1.bc0ef38704cbbp+180, 0x1.383a833aef5f3p+186,
+ 0x1.c0d41ca4b818ep+191, 0x1.499bc508f7324p+197,
+ 0x1.ee69a78d72cb6p+202, 0x1.7a88e4484be3bp+208,
+ 0x1.27baf2587b49ep+214, 0x1.d751f23d047dcp+219,
+ 0x1.7ef294d193a63p+225, 0x1.3d20e33d8e45ap+231,
+ 0x1.0b93bfbbf00acp+237, 0x1.cbe5f18b04928p+242,
+ 0x1.92693359a4003p+248, 0x1.6665b1bbd6102p+254,
+ 0x1.44cc291239feap+260, 0x1.2b6c35dccd76cp+266,
+ 0x1.18b5727f009f5p+272, 0x1.0b8cf1210c97ep+278,
+ 0x1.0330899804332p+284, 0x1.fe478ee34844ap+289,
+ 0x1.fe478ee34844ap+295, 0x1.0320568f6ab2ep+302,
+ 0x1.0b395943e6087p+308, 0x1.17c0097314d0dp+314,
+ 0x1.293c0a0a461dep+320, 0x1.4074bad313983p+326,
+ 0x1.5e7fac56dd6e8p+332, 0x1.84d5a3305da69p+338,
+ 0x1.b5705796695b6p+344, 0x1.f2f423e7902c4p+350,
+ 0x1.207524c1df599p+357, 0x1.5209471331bd0p+363,
+ 0x1.916b0466cb107p+369, 0x1.e2f4c14bac4fcp+375,
+ 0x1.264d25ca1d009p+382, 0x1.6b473aa57bcccp+388,
+ 0x1.c619094edabffp+394, 0x1.1f5bd7e3e66d7p+401,
+ 0x1.702dac9bff3c4p+407, 0x1.dd7b3bda4f022p+413,
+ 0x1.3958df4743d96p+420, 0x1.a02a088aa61cbp+426,
+ 0x1.179c3dbd279b5p+433, 0x1.7c1863ed21d72p+439,
+ 0x1.0550c4b30743ep+446, 0x1.6b645188f61a6p+452,
+ 0x1.ff0512a89a152p+458, 0x1.6b4d9b43dd8b0p+465,
+ 0x1.051fc798c73bfp+472, 0x1.7b722e0a01831p+478,
+ 0x1.16a7d9cf591c4p+485, 0x1.9da1274fc845fp+491,
+ 0x1.3638dd7bd6347p+498, 0x1.d62e2fafb0a78p+504,
+ 0x1.67fb5c8283404p+511, 0x1.166c698cf183bp+518,
+ 0x1.b30964ec395dcp+524, 0x1.574569a265440p+531,
+ 0x1.118b502d68b23p+538, 0x1.b83c3509147ecp+544,
+ 0x1.65b0eb1760a70p+551, 0x1.256b20d92d490p+558,
+ 0x1.e5f96e67b300ep+564, 0x1.963e824aafa2cp+571,
+ 0x1.56c4bdef04315p+578, 0x1.23e389bd89920p+585,
+ 0x1.f5af14bdc472fp+591, 0x1.b30dd3fc905bap+598,
+ 0x1.7cac197cfe503p+605, 0x1.500fee805882dp+612,
+ 0x1.2b4e306a4ed48p+619, 0x1.0ce83f7f82d2fp+626,
+ 0x1.e764f3171d1e4p+632, 0x1.bd824633209dbp+639,
+ 0x1.9ab418b722116p+646, 0x1.7dd36efa41ac2p+653,
+ 0x1.65f6380a9d916p+660, 0x1.5262c0fa08f37p+667,
+ 0x1.42861fee50880p+674, 0x1.35ece2af0162bp+681,
+ 0x1.2c3d7b998957ap+688, 0x1.25340ab3f01f9p+695,
+ 0x1.209f3a89205f1p+702, 0x1.1e5dfc140e1e5p+709,
+ 0x1.1e5dfc140e1e5p+716, 0x1.209ab80c363a9p+723,
+ 0x1.251d22ec67138p+730, 0x1.2bfbd1bdf17dfp+737,
+ 0x1.355bb04be109ep+744, 0x1.4171452ed7d44p+751,
+ 0x1.5082946d09f23p+758, 0x1.62e9b88b007d7p+765,
+ 0x1.79185413b0855p+772, 0x1.939c09fd12eebp+779,
+ 0x1.b3243ac4d8695p+786, 0x1.d88957d1c3026p+793,
+ 0x1.026b1c06b6a55p+801, 0x1.1ca9fcdf65321p+808,
+ 0x1.3bcc9487d4439p+815, 0x1.60ce8defbf238p+822,
+ 0x1.8ce85fadb707ep+829, 0x1.c19f3c62c956fp+836,
+ 0x1.006cd07056d39p+844, 0x1.267cf76103b70p+851,
+ 0x1.54807e082c4b9p+858, 0x1.8c5d92b583900p+865,
+ 0x1.d07da7ecb62ccp+872, 0x1.11fa1e0c9f746p+880,
+ 0x1.455903aefd5a3p+887, 0x1.84e466672ad5dp+894,
+ 0x1.d3e2cb341f894p+901, 0x1.1b4a51088f182p+909,
+ 0x1.594292c26e656p+916, 0x1.a77ba8027b686p+923,
+ 0x1.055e51b1882a7p+931, 0x1.44ab297a8724bp+938,
+ 0x1.95d5f3d928edep+945, 0x1.fe771cb7257b3p+952,
+ 0x1.4307602be5b7fp+960, 0x1.9b5b6477e6884p+967,
+ 0x1.07868c5ccfaf4p+975, 0x1.53b370efa3b7fp+982,
+ 0x1.b88cb676c8529p+989, 0x1.1f63cb077cadep+997,
+ 0x1.7932fa79d3a43p+1004, 0x1.f2054eb4d96ecp+1011,
+ 0x1.4ab7864418639p+1019};
+
+ // It is safe to cast to int at this point because any integer
+ // reaching this part of the code is at most 171 because of the
+ // overflow check above.
+ if (LIBC_UNLIKELY(x > 0.0 && fputil::nearest_integer(x) == x)) {
+ return FACTORIALS[static_cast<int>(x) - 1];
+ }
+
// TODO: Implement tgamma for the remaining input ranges
return 0.0;
}
>From f0f3515f81d13c1844fee20fbb76f26268fc8db9 Mon Sep 17 00:00:00 2001
From: Hardik Chona <iamhardikchona at gmail.com>
Date: Wed, 22 Jul 2026 16:38:16 +0530
Subject: [PATCH 11/13] [libc][math] Wire up MPFR
---
libc/utils/MPFRWrapper/MPCommon.cpp | 6 ++++++
libc/utils/MPFRWrapper/MPCommon.h | 1 +
libc/utils/MPFRWrapper/MPFRUtils.cpp | 2 ++
libc/utils/MPFRWrapper/MPFRUtils.h | 1 +
4 files changed, 10 insertions(+)
diff --git a/libc/utils/MPFRWrapper/MPCommon.cpp b/libc/utils/MPFRWrapper/MPCommon.cpp
index 2422bcf45222f..1f00ac0d0dc0d 100644
--- a/libc/utils/MPFRWrapper/MPCommon.cpp
+++ b/libc/utils/MPFRWrapper/MPCommon.cpp
@@ -317,6 +317,12 @@ MPFRNumber MPFRNumber::frexp(int &exp) {
return result;
}
+MPFRNumber MPFRNumber::gamma() const {
+ MPFRNumber result(*this);
+ mpfr_gamma(result.value, value, mpfr_rounding);
+ return result;
+}
+
MPFRNumber MPFRNumber::hypot(const MPFRNumber &b) {
MPFRNumber result(*this);
mpfr_hypot(result.value, value, b.value, mpfr_rounding);
diff --git a/libc/utils/MPFRWrapper/MPCommon.h b/libc/utils/MPFRWrapper/MPCommon.h
index 38fd15fcc956c..69e1001c00924 100644
--- a/libc/utils/MPFRWrapper/MPCommon.h
+++ b/libc/utils/MPFRWrapper/MPCommon.h
@@ -211,6 +211,7 @@ class MPFRNumber {
MPFRNumber floor() const;
MPFRNumber fmod(const MPFRNumber &b);
MPFRNumber frexp(int &exp);
+ MPFRNumber gamma() const;
MPFRNumber hypot(const MPFRNumber &b);
MPFRNumber lgamma() const;
MPFRNumber log() const;
diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp
index d585baa2e0d2c..0e51e3a02963b 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.cpp
+++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp
@@ -115,6 +115,8 @@ unary_operation(Operation op, InputType input, unsigned int precision,
return mpfrInput.tanh();
case Operation::Tanpi:
return mpfrInput.tanpi();
+ case Operation::Tgamma:
+ return mpfrInput.gamma();
case Operation::Trunc:
return mpfrInput.trunc();
default:
diff --git a/libc/utils/MPFRWrapper/MPFRUtils.h b/libc/utils/MPFRWrapper/MPFRUtils.h
index 84e59674295f5..55afa33687738 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.h
+++ b/libc/utils/MPFRWrapper/MPFRUtils.h
@@ -68,6 +68,7 @@ enum class Operation : int {
Tan,
Tanh,
Tanpi,
+ Tgamma,
Trunc,
EndUnaryOperationsSingleOutput,
>From 277af70eb3eb3a8ea886c0cfef410f15bd6940c7 Mon Sep 17 00:00:00 2001
From: Hardik Chona <iamhardikchona at gmail.com>
Date: Wed, 22 Jul 2026 16:50:33 +0530
Subject: [PATCH 12/13] [libc][math] Set up tgamma_test.cpp, add it to
CMakeLists.txt, and write the test for positive integers
formatting: add new line at end
Add constexpr
---
libc/test/src/math/CMakeLists.txt | 12 ++++++++++++
libc/test/src/math/tgamma_test.cpp | 28 ++++++++++++++++++++++++++++
2 files changed, 40 insertions(+)
create mode 100644 libc/test/src/math/tgamma_test.cpp
diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index 240689c0de02f..f2f22a3301997 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -278,6 +278,18 @@ add_fp_unittest(
libc.src.math.tanpif16
)
+add_fp_unittest(
+ tgamma_test
+ NEED_MPFR
+ SUITE
+ libc-math-unittests
+ SRCS
+ tgamma_test.cpp
+ DEPENDS
+ libc.src.math.tgamma
+ libc.src.__support.FPUtil.fp_bits
+)
+
add_fp_unittest(
fabs_test
NEED_MPFR
diff --git a/libc/test/src/math/tgamma_test.cpp b/libc/test/src/math/tgamma_test.cpp
new file mode 100644
index 0000000000000..aa484ba38c1ec
--- /dev/null
+++ b/libc/test/src/math/tgamma_test.cpp
@@ -0,0 +1,28 @@
+//===-- Unittests for tgamma ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/math/tgamma.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+
+using LlvmLibcTgammaTest = LIBC_NAMESPACE::testing::FPTest<double>;
+
+namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
+
+TEST_F(LlvmLibcTgammaTest, PositiveIntegers) {
+ // 171 is the maximum integer input for which
+ // tgamma returns a finite output.
+ constexpr int N = 171;
+ for (int i = 1; i <= N; i++) {
+ double x = static_cast<double>(i);
+ EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Tgamma, x,
+ LIBC_NAMESPACE::tgamma(x), 0.5);
+ }
+}
>From bdc58ef18d3b3297fc9d0de5511411ca801a828d Mon Sep 17 00:00:00 2001
From: Hardik Chona <iamhardikchona at gmail.com>
Date: Wed, 22 Jul 2026 17:03:07 +0530
Subject: [PATCH 13/13] [libc][math] Change EXPECT_MPFR_MATCH_ALL_ROUNDING to
EXPECT_MPFR_MATCH
Positive integers' factorials in the implementation are pre-computed correctly rounded to nearest only.
---
libc/test/src/math/tgamma_test.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libc/test/src/math/tgamma_test.cpp b/libc/test/src/math/tgamma_test.cpp
index aa484ba38c1ec..2e3a7e7a9489f 100644
--- a/libc/test/src/math/tgamma_test.cpp
+++ b/libc/test/src/math/tgamma_test.cpp
@@ -22,7 +22,7 @@ TEST_F(LlvmLibcTgammaTest, PositiveIntegers) {
constexpr int N = 171;
for (int i = 1; i <= N; i++) {
double x = static_cast<double>(i);
- EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Tgamma, x,
+ EXPECT_MPFR_MATCH(mpfr::Operation::Tgamma, x,
LIBC_NAMESPACE::tgamma(x), 0.5);
}
}
More information about the libc-commits
mailing list