[libcxx-commits] [libcxx] [libc++][math][c++17] P0226R1 - Mathematical Special Functions: infra + `std::assoc_laguerre` (PR #205649)
via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Jun 26 09:27:55 PDT 2026
https://github.com/PaulXiCao updated https://github.com/llvm/llvm-project/pull/205649
>From 7555447d01b3e6bd5127f4ffbfaeeb223cf9ea81 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 23 Jun 2026 20:52:48 +0200
Subject: [PATCH 1/8] link against Boost.Math
---
libcxx/CMakeLists.txt | 8 ++++++++
libcxx/src/CMakeLists.txt | 2 ++
2 files changed, 10 insertions(+)
diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt
index 845240d1b894c..845042f15495f 100644
--- a/libcxx/CMakeLists.txt
+++ b/libcxx/CMakeLists.txt
@@ -899,6 +899,14 @@ add_custom_target(cxx-test-depends
COMMENT "Build dependencies required to run the libc++ test suite.")
add_subdirectory(include)
+
+# Header-only Boost.Math (INTERFACE target `boost_math`). Lives outside the
+# libcxx source tree, so a binary dir must be supplied.
+add_subdirectory(
+ ${LLVM_THIRD_PARTY_DIR}/boost-math
+ ${LIBCXX_BINARY_DIR}/third-party/boost-math
+ EXCLUDE_FROM_ALL)
+
add_subdirectory(src)
add_subdirectory(utils)
add_subdirectory(modules)
diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt
index de7817ad69f26..c882446596a3e 100644
--- a/libcxx/src/CMakeLists.txt
+++ b/libcxx/src/CMakeLists.txt
@@ -176,6 +176,7 @@ add_library(cxx_shared SHARED ${LIBCXX_SOURCES} ${LIBCXX_HEADERS})
target_include_directories(cxx_shared PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(cxx_shared PUBLIC cxx-headers runtimes-libc-shared
PRIVATE ${LIBCXX_LIBRARIES}
+ PRIVATE boost_math
PRIVATE llvm-libc-common-utilities)
set_target_properties(cxx_shared
PROPERTIES
@@ -263,6 +264,7 @@ add_library(cxx_static STATIC ${LIBCXX_SOURCES} ${LIBCXX_HEADERS})
target_include_directories(cxx_static PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(cxx_static PUBLIC cxx-headers runtimes-libc-static
PRIVATE ${LIBCXX_LIBRARIES}
+ PRIVATE boost_math
PRIVATE libcxx-abi-static
PRIVATE llvm-libc-common-utilities)
set_target_properties(cxx_static
>From fe89c404516cfea93ab67939b48a15c74213cd59 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 23 Jun 2026 20:53:37 +0200
Subject: [PATCH 2/8] add empty src/mathematical_special_functions.cpp
---
libcxx/src/CMakeLists.txt | 1 +
libcxx/src/mathematical_special_functions.cpp | 17 +++++++++++++++++
2 files changed, 18 insertions(+)
create mode 100644 libcxx/src/mathematical_special_functions.cpp
diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt
index c882446596a3e..d2168decbfdba 100644
--- a/libcxx/src/CMakeLists.txt
+++ b/libcxx/src/CMakeLists.txt
@@ -29,6 +29,7 @@ set(LIBCXX_SOURCES
include/ryu/ryu.h
include/to_chars_floating_point.h
include/from_chars_floating_point.h
+ mathematical_special_functions.cpp
memory.cpp
memory_resource.cpp
new_handler.cpp
diff --git a/libcxx/src/mathematical_special_functions.cpp b/libcxx/src/mathematical_special_functions.cpp
new file mode 100644
index 0000000000000..db07d61f89319
--- /dev/null
+++ b/libcxx/src/mathematical_special_functions.cpp
@@ -0,0 +1,17 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 <__config>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+
+namespace {}
+
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
>From 7fbc20f4bea5a80fdebfb22eadee50cb90698b46 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 23 Jun 2026 21:06:04 +0200
Subject: [PATCH 3/8] add simple test for std::assoc_laguerref (fails atm)
---
.../c.math/sf.cmath/assoc_laguerre.pass.cpp | 27 +++++++++++++++++++
1 file changed, 27 insertions(+)
create mode 100644 libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
new file mode 100644
index 0000000000000..1a12c8f81a16c
--- /dev/null
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// Missing powl
+// XFAIL: LLVM-LIBC-FIXME
+
+// REQUIRES: std-at-least-c++17
+
+// <cmath>
+//
+// [sf.cmath.assoc.laguerre], associated Laguerre polynomials
+// floating-point-type assoc_laguerre(unsigned n, unsigned m, floating-point-type x);
+// float assoc_laguerref(unsigned n, unsigned m, float x);
+// long double assoc_laguerrel(unsigned n, unsigned m, long double x);
+
+#include <cmath>
+
+int main(int, char**) {
+ std::assoc_laguerref(0, 0, 0.0f);
+
+ return 0;
+}
>From c7e11e92b9c70fe1f319a8f959ce1c11cbbfa9cc Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 23 Jun 2026 21:52:09 +0200
Subject: [PATCH 4/8] handling MATH_ERRNO, MATH_ERREXCEPT via __sf_result
---
libcxx/include/__math/special_functions.h | 25 +++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h
index 6b217852e2f8c..86b3ac9cb665e 100644
--- a/libcxx/include/__math/special_functions.h
+++ b/libcxx/include/__math/special_functions.h
@@ -15,7 +15,10 @@
#include <__math/traits.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/is_integral.h>
+#include <cerrno>
+#include <cfenv>
#include <limits>
+#include <math.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -25,6 +28,28 @@ _LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 17
+namespace __math {
+template <class _Tp>
+struct __sf_result {
+ bool __domain_error;
+ _Tp __ret;
+
+ operator _Tp() const {
+# if math_errhandling & MATH_ERRNO
+ if (__domain_error)
+ errno = EDOM;
+# endif
+
+# if math_errhandling & MATH_ERREXCEPT
+ if (__domain_error)
+ feraiseexcept(FE_INVALID);
+# endif
+
+ return __ret;
+ }
+};
+} // namespace __math
+
template <class _Real>
_LIBCPP_HIDE_FROM_ABI _Real __hermite(unsigned __n, _Real __x) {
// The Hermite polynomial H_n(x).
>From 23081681878b007cb50f1ed115ec316fa956b4cf Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 23 Jun 2026 22:00:10 +0200
Subject: [PATCH 5/8] impl assoc_laguerref
---
libcxx/include/__math/special_functions.h | 9 +++++
libcxx/src/mathematical_special_functions.cpp | 37 ++++++++++++++++++-
2 files changed, 45 insertions(+), 1 deletion(-)
diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h
index 86b3ac9cb665e..d0d6e56507e85 100644
--- a/libcxx/include/__math/special_functions.h
+++ b/libcxx/include/__math/special_functions.h
@@ -25,6 +25,7 @@
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
#if _LIBCPP_STD_VER >= 17
@@ -48,8 +49,15 @@ struct __sf_result {
return __ret;
}
};
+
+_LIBCPP_EXPORTED_FROM_ABI __sf_result<float> __assoc_laguerre(unsigned int, unsigned int, float) noexcept;
+
} // namespace __math
+inline _LIBCPP_HIDE_FROM_ABI float assoc_laguerref(unsigned int __n, unsigned int __m, float __x) noexcept {
+ return __math::__assoc_laguerre(__n, __m, __x);
+}
+
template <class _Real>
_LIBCPP_HIDE_FROM_ABI _Real __hermite(unsigned __n, _Real __x) {
// The Hermite polynomial H_n(x).
@@ -104,6 +112,7 @@ _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, _Integer __x) {
#endif // _LIBCPP_STD_VER >= 17
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP___MATH_SPECIAL_FUNCTIONS_H
diff --git a/libcxx/src/mathematical_special_functions.cpp b/libcxx/src/mathematical_special_functions.cpp
index db07d61f89319..e18e9c5f2797c 100644
--- a/libcxx/src/mathematical_special_functions.cpp
+++ b/libcxx/src/mathematical_special_functions.cpp
@@ -7,11 +7,46 @@
//===----------------------------------------------------------------------===//
#include <__config>
+#include <boost/math/special_functions.hpp>
+#include <cmath>
+#include <optional>
+#include <type_traits>
_LIBCPP_BEGIN_NAMESPACE_STD
_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
-namespace {}
+namespace __math {
+namespace {
+template <class _Ret>
+optional<_Ret> __check_nan() {
+ return nullopt;
+}
+
+template <class _Ret, class _Arg, class... _Args>
+optional<_Ret> __check_nan(_Arg __arg, _Args... __args) {
+ if constexpr (is_floating_point_v<_Arg>)
+ if (isnan(__arg))
+ return __arg;
+ return __check_nan<_Ret>(__args...);
+}
+
+template <class Func, class... _Args, class _Ret = std::invoke_result_t<Func, _Args...>>
+__sf_result<_Ret> invoke_boost_math(Func f, _Args... __args) {
+ if (auto __maybe_nan = __check_nan<_Ret>(__args...); __maybe_nan.has_value())
+ return {.__domain_error = false, .__ret = *__maybe_nan};
+
+ try {
+ return {.__domain_error = false, .__ret = f(__args...)};
+ } catch (...) {
+ return {.__domain_error = true, .__ret = numeric_limits<_Ret>::quiet_NaN()};
+ }
+}
+} // namespace
+
+__sf_result<float> __assoc_laguerre(unsigned int __n, unsigned int __m, float __x) noexcept {
+ return invoke_boost_math([&](auto... __args) { return boost::math::laguerre(__args...); }, __n, __m, __x);
+}
+} // namespace __math
_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
_LIBCPP_END_NAMESPACE_STD
>From adb174a0e9d29b172b17bc9e0d781db0dff15d5c Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 23 Jun 2026 22:34:12 +0200
Subject: [PATCH 6/8] test assoc_laguerref
---
.../c.math/sf.cmath/assoc_laguerre.pass.cpp | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
index 1a12c8f81a16c..fe92daa501c6f 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
@@ -6,22 +6,18 @@
//
//===----------------------------------------------------------------------===//
-// Missing powl
-// XFAIL: LLVM-LIBC-FIXME
-
// REQUIRES: std-at-least-c++17
// <cmath>
//
// [sf.cmath.assoc.laguerre], associated Laguerre polynomials
-// floating-point-type assoc_laguerre(unsigned n, unsigned m, floating-point-type x);
// float assoc_laguerref(unsigned n, unsigned m, float x);
-// long double assoc_laguerrel(unsigned n, unsigned m, long double x);
+#include <cassert>
#include <cmath>
-int main(int, char**) {
- std::assoc_laguerref(0, 0, 0.0f);
-
- return 0;
+int main() {
+ // Single value tested against known solution.
+ // Note, underlying Boost.Math is itself well-tested.
+ assert(std::abs(std::assoc_laguerref(2, 10, 0.5f) - 60.125f) < 0.001f);
}
>From b7bc1fb6247235ce62066d70a30c13608a8672fc Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 26 Jun 2026 18:26:00 +0200
Subject: [PATCH 7/8] test: common.h
---
.../std/numerics/c.math/sf.cmath/common.h | 65 +++++++++++++++++++
1 file changed, 65 insertions(+)
create mode 100644 libcxx/test/std/numerics/c.math/sf.cmath/common.h
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/common.h b/libcxx/test/std/numerics/c.math/sf.cmath/common.h
new file mode 100644
index 0000000000000..867e6af6f6914
--- /dev/null
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/common.h
@@ -0,0 +1,65 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 TEST_SF_CMATH_COMMON_H
+#define TEST_SF_CMATH_COMMON_H
+
+#include <cassert>
+#include <cerrno>
+#include <cmath>
+#include <math.h>
+#include <cfenv>
+
+// std::type_identity is C++20 (we need to support C++17 here)
+template <class T>
+struct type_identity {
+ typedef T type;
+};
+template <class T>
+using type_identity_t = typename type_identity<T>::type;
+
+template <class T>
+bool between(type_identity_t<T> lower, T value, type_identity_t<T> upper) {
+ return lower < value && value < upper;
+}
+
+template <class Func>
+void check_no_domain_error(Func f) {
+#if math_errhandling & MATH_ERRNO
+ errno = EACCES;
+#endif
+#if math_errhandling & MATH_ERREXCEPT
+ std::feclearexcept(FE_INVALID);
+#endif
+ f();
+#if math_errhandling & MATH_ERRNO
+ assert(errno == EACCES);
+#endif
+#if math_errhandling & MATH_ERREXCEPT
+ assert(!std::fetestexcept(FE_INVALID));
+#endif
+}
+
+template <class Func>
+void check_domain_error(Func f) {
+#if math_errhandling & MATH_ERRNO
+ errno = EACCES;
+#endif
+#if math_errhandling & MATH_ERREXCEPT
+ std::feclearexcept(FE_INVALID);
+#endif
+ f();
+#if math_errhandling & MATH_ERRNO
+ assert(errno == EDOM);
+#endif
+#if math_errhandling & MATH_ERREXCEPT
+ assert(std::fetestexcept(FE_INVALID));
+#endif
+}
+
+#endif // TEST_SF_CMATH_COMMON_H
>From a47f9e902e5c427c84115f4af119eedf8778e182 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 26 Jun 2026 18:26:59 +0200
Subject: [PATCH 8/8] more testing of assoc_laguerref: values, types, domain
error
---
.../c.math/sf.cmath/assoc_laguerre.pass.cpp | 36 +++++++++++++++++--
1 file changed, 33 insertions(+), 3 deletions(-)
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
index fe92daa501c6f..eb747efb4c1c6 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
@@ -14,10 +14,40 @@
// float assoc_laguerref(unsigned n, unsigned m, float x);
#include <cassert>
+#include <cerrno>
+#include <cfenv>
#include <cmath>
+#include "common.h"
+#include "type_algorithms.h"
+
+struct TestFloatingPoint {
+ template <class T>
+ void operator()() const {
+ assert(between(0.99f, std::assoc_laguerref(0, 0, T(0.)), 1.01f));
+
+ assert(between(0.99f, std::assoc_laguerref(1, 1, T(1.)), 1.01f));
+
+ assert(between(-0.01f, std::assoc_laguerref(2, 2, T(2.)), 0.01f));
+
+ assert(std::abs(std::assoc_laguerref(2, 10, 0.5f) - 60.125f) < 0.001f);
+
+ static_assert(std::is_same_v<decltype(std::assoc_laguerref(0, 0, T(0.))), float>);
+
+ check_no_domain_error([] { (void)std::assoc_laguerref(0, 0, std::numeric_limits<T>::quiet_NaN()); });
+ }
+};
+
+struct TestIntegral {
+ template <class T>
+ void operator()() const {
+ assert(between(0.99f, std::assoc_laguerref(0, 0, T(0.)), 1.01f));
+
+ static_assert(std::is_same_v<decltype(std::assoc_laguerref(0, 0, T(0.))), float>);
+ }
+};
+
int main() {
- // Single value tested against known solution.
- // Note, underlying Boost.Math is itself well-tested.
- assert(std::abs(std::assoc_laguerref(2, 10, 0.5f) - 60.125f) < 0.001f);
+ types::for_each(types::floating_point_types{}, TestFloatingPoint{});
+ types::for_each(types::integral_types{}, TestIntegral{});
}
More information about the libcxx-commits
mailing list