From 945d456aa1bd096a31728542e695dc4d5793d4f8 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 26 Aug 2021 20:47:47 +0300 Subject: [PATCH 1/6] Initial commit --- include/boost/math/ccmath/ccmath.hpp | 1 + include/boost/math/ccmath/frexp.hpp | 98 ++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 include/boost/math/ccmath/frexp.hpp diff --git a/include/boost/math/ccmath/ccmath.hpp b/include/boost/math/ccmath/ccmath.hpp index bdcd895620..37b613dfd6 100644 --- a/include/boost/math/ccmath/ccmath.hpp +++ b/include/boost/math/ccmath/ccmath.hpp @@ -15,5 +15,6 @@ #include #include #include +#include #endif // BOOST_MATH_CCMATH diff --git a/include/boost/math/ccmath/frexp.hpp b/include/boost/math/ccmath/frexp.hpp new file mode 100644 index 0000000000..de2c91d1ee --- /dev/null +++ b/include/boost/math/ccmath/frexp.hpp @@ -0,0 +1,98 @@ +// (C) Copyright Christopher Kormanyos 1999 - 2021. +// (C) Copyright Matt Borland 2021. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_CCMATH_FREXP_HPP +#define BOOST_MATH_CCMATH_FREXP_HPP + +#include +#include +#include +#include +#include +#include + +namespace boost::math::ccmath { + +namespace detail +{ + +template +inline constexpr Real frexp_zero_impl(Real arg, int* exp) +{ + *exp = 0; + return arg; +} + +template +inline constexpr Real frexp_impl(Real arg, int* exp) +{ + constexpr bool negative_arg = arg < Real(0); + + Real f = negative_arg ? -arg : arg; + int e2 = 0; + constexpr Real two_pow_32 = Real(4294967296); + + while (f >= two_pow_32) + { + f = f / two_pow_32; + e2 += 32; + } + + while(f >= Real(1)) + { + f = f / Real(2); + ++e2; + } + + if(exp != nullptr) + { + *exp = e2; + } + + return !negative_arg ? f : -f; +} + +} // namespace detail + +template , bool> == true> +inline constexpr Real frexp(Real arg, int* exp) +{ + if(BOOST_MATH_IS_CONSTANT_EVALUATED(arg)) + { + return arg == T(0) ? detail::frexp_zero_impl(arg, &exp) : + arg == T(-0) ? detail::frexp_zero_impl(arg, &exp) : + boost::math::ccmath::isinf(arg) ? detail::frexp_zero_impl(arg, &exp) : + boost::math::ccmath::isnan(arg) ? detail::frexp_zero_impl(arg, &exp) : + boost::math::ccmath::detail::frexp_impl(arg, &exp); + } + else + { + using std::frexp; + return frexp(arg, &exp); + } +} + +template , bool> == true> +inline constexpr double frexp(Z arg, int* exp) +{ + return boost::math::ccmath::frexp(static_cast(arg), &exp); +} + +inline constexpr float frexpf(float arg, int* exp) +{ + return boost::math::ccmath::frexp(arg, &exp); +} + +#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS +inline constexpr float frexpl(long double arg, int* exp) +{ + return boost::math::ccmath::frexp(arg, &exp); +} +#endif + +} + +#endif // BOOST_MATH_CCMATH_FREXP_HPP From 8238fd87076374a5a527395539c9fdcf0dd35784 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 31 Aug 2021 21:19:34 +0300 Subject: [PATCH 2/6] Add include test --- doc/sf/ccmath.qbk | 6 +++++ include/boost/math/ccmath/frexp.hpp | 24 ++++++++++---------- test/compile_test/ccmath_frexp_incl_test.cpp | 17 ++++++++++++++ 3 files changed, 35 insertions(+), 12 deletions(-) create mode 100644 test/compile_test/ccmath_frexp_incl_test.cpp diff --git a/doc/sf/ccmath.qbk b/doc/sf/ccmath.qbk index 62bcc1ac9d..86abd53cbc 100644 --- a/doc/sf/ccmath.qbk +++ b/doc/sf/ccmath.qbk @@ -51,6 +51,12 @@ All of the following functions require C++17 or greater. template inline constexpr int fpclassify(T x); + template + inline constexpr Real frexp(Real arg, int* exp); + + template + inline constexpr double frexp(Z arg, int* exp); + } // Namespaces [endsect] [/section:ccmath Constexpr CMath] diff --git a/include/boost/math/ccmath/frexp.hpp b/include/boost/math/ccmath/frexp.hpp index de2c91d1ee..3798987533 100644 --- a/include/boost/math/ccmath/frexp.hpp +++ b/include/boost/math/ccmath/frexp.hpp @@ -29,7 +29,7 @@ inline constexpr Real frexp_zero_impl(Real arg, int* exp) template inline constexpr Real frexp_impl(Real arg, int* exp) { - constexpr bool negative_arg = arg < Real(0); + const bool negative_arg = (arg < 0); Real f = negative_arg ? -arg : arg; int e2 = 0; @@ -57,39 +57,39 @@ inline constexpr Real frexp_impl(Real arg, int* exp) } // namespace detail -template , bool> == true> +template , bool> = true> inline constexpr Real frexp(Real arg, int* exp) { if(BOOST_MATH_IS_CONSTANT_EVALUATED(arg)) { - return arg == T(0) ? detail::frexp_zero_impl(arg, &exp) : - arg == T(-0) ? detail::frexp_zero_impl(arg, &exp) : - boost::math::ccmath::isinf(arg) ? detail::frexp_zero_impl(arg, &exp) : - boost::math::ccmath::isnan(arg) ? detail::frexp_zero_impl(arg, &exp) : - boost::math::ccmath::detail::frexp_impl(arg, &exp); + return arg == Real(0) ? detail::frexp_zero_impl(arg, exp) : + arg == Real(-0) ? detail::frexp_zero_impl(arg, exp) : + boost::math::ccmath::isinf(arg) ? detail::frexp_zero_impl(arg, exp) : + boost::math::ccmath::isnan(arg) ? detail::frexp_zero_impl(arg, exp) : + boost::math::ccmath::detail::frexp_impl(arg, exp); } else { using std::frexp; - return frexp(arg, &exp); + return frexp(arg, exp); } } -template , bool> == true> +template , bool> = true> inline constexpr double frexp(Z arg, int* exp) { - return boost::math::ccmath::frexp(static_cast(arg), &exp); + return boost::math::ccmath::frexp(static_cast(arg), exp); } inline constexpr float frexpf(float arg, int* exp) { - return boost::math::ccmath::frexp(arg, &exp); + return boost::math::ccmath::frexp(arg, exp); } #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS inline constexpr float frexpl(long double arg, int* exp) { - return boost::math::ccmath::frexp(arg, &exp); + return boost::math::ccmath::frexp(arg, exp); } #endif diff --git a/test/compile_test/ccmath_frexp_incl_test.cpp b/test/compile_test/ccmath_frexp_incl_test.cpp new file mode 100644 index 0000000000..a273d919f2 --- /dev/null +++ b/test/compile_test/ccmath_frexp_incl_test.cpp @@ -0,0 +1,17 @@ +// (C) Copyright Matt Borland 2021. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include "test_compile_result.hpp" + +void compile_and_link_test() +{ + int i; + check_result(boost::math::ccmath::frexp(1.0f, &i)); + check_result(boost::math::ccmath::frexp(1.0, &i)); +#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS + check_result(boost::math::ccmath::frexp(1.0l, &i)); +#endif +} From 4eb6ca5defadaf3f03c668c07786e38e9ae7160b Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 2 Sep 2021 21:27:50 +0300 Subject: [PATCH 3/6] Add test set [CI SKIP] --- include/boost/math/ccmath/frexp.hpp | 2 +- test/Jamfile.v2 | 1 + test/ccmath_frexp_test.cpp | 54 +++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 test/ccmath_frexp_test.cpp diff --git a/include/boost/math/ccmath/frexp.hpp b/include/boost/math/ccmath/frexp.hpp index 3798987533..791612a37b 100644 --- a/include/boost/math/ccmath/frexp.hpp +++ b/include/boost/math/ccmath/frexp.hpp @@ -29,7 +29,7 @@ inline constexpr Real frexp_zero_impl(Real arg, int* exp) template inline constexpr Real frexp_impl(Real arg, int* exp) { - const bool negative_arg = (arg < 0); + const bool negative_arg = (arg < Real(0)); Real f = negative_arg ? -arg : arg; int e2 = 0; diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 52fb87f5e5..f867dd882d 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -128,6 +128,7 @@ test-suite special_fun : [ run ccmath_isfinite_test.cpp ../../test/build//boost_unit_test_framework : : : [ requires cxx17_if_constexpr ] ] [ run ccmath_isnormal_test.cpp ../../test/build//boost_unit_test_framework : : : [ requires cxx17_if_constexpr ] ] [ run ccmath_fpclassify_test.cpp ../../test/build//boost_unit_test_framework : : : [ requires cxx17_if_constexpr ] ] + [ run ccmath_frexp_test.cpp ../../test/build//boost_unit_test_framework : : : [ requires cxx17_if_constexpr ] ] [ run log1p_expm1_test.cpp test_instances//test_instances pch_light ../../test/build//boost_unit_test_framework ] [ run powm1_sqrtp1m1_test.cpp test_instances//test_instances pch_light ../../test/build//boost_unit_test_framework ] [ run special_functions_test.cpp ../../test/build//boost_unit_test_framework ] diff --git a/test/ccmath_frexp_test.cpp b/test/ccmath_frexp_test.cpp new file mode 100644 index 0000000000..59a1601192 --- /dev/null +++ b/test/ccmath_frexp_test.cpp @@ -0,0 +1,54 @@ +// (C) Copyright Matt Borland 2021. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_FLOAT128 +#include +#endif + +template +void test() +{ + static int i; + if constexpr (std::numeric_limits::has_quiet_NaN) + { + static_assert(boost::math::ccmath::isnan(boost::math::ccmath::frexp(std::numeric_limits::quiet_NaN(), &i))); + } + + static_assert(boost::math::ccmath::frexp(0, &i) == 0); + static_assert(boost::math::ccmath::isinf(boost::math::ccmath::frexp(std::numeric_limits::infinity(), &i))); + static_assert(boost::math::ccmath::frexp(T(1024), &i) == T(0.5)); +} + +#ifndef BOOST_MATH_NO_CONSTEXPR_DETECTION +int main() +{ + test(); + test(); + + #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS + test(); + #endif + + #if defined(BOOST_HAS_FLOAT128) && !defined(BOOST_MATH_USING_BUILTIN_CONSTANT_P) + test(); + #endif + + return 0; +} +#else +int main() +{ + return 0; +} +#endif From ff3aa3a806eeafe7d795ef6b6ffccbe170be5f44 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Sun, 5 Sep 2021 17:24:22 +0300 Subject: [PATCH 4/6] Fix testing methods --- test/ccmath_frexp_test.cpp | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/test/ccmath_frexp_test.cpp b/test/ccmath_frexp_test.cpp index 59a1601192..a94bca108b 100644 --- a/test/ccmath_frexp_test.cpp +++ b/test/ccmath_frexp_test.cpp @@ -17,17 +17,43 @@ #endif template -void test() +inline constexpr T base_helper(const T val) +{ + int i = 0; + const T ans = boost::math::ccmath::frexp(val, &i); + + return ans; +} + +template +inline constexpr int exp_helper(const T val) +{ + int i = 0; + boost::math::ccmath::frexp(val, &i); + + return i; +} + +template +constexpr void test() { - static int i; if constexpr (std::numeric_limits::has_quiet_NaN) { - static_assert(boost::math::ccmath::isnan(boost::math::ccmath::frexp(std::numeric_limits::quiet_NaN(), &i))); + static_assert(boost::math::ccmath::isnan(base_helper(std::numeric_limits::quiet_NaN())), "If the arg is NaN, NaN is returned"); } - static_assert(boost::math::ccmath::frexp(0, &i) == 0); - static_assert(boost::math::ccmath::isinf(boost::math::ccmath::frexp(std::numeric_limits::infinity(), &i))); - static_assert(boost::math::ccmath::frexp(T(1024), &i) == T(0.5)); + static_assert(!base_helper(T(0)), "If the arg is +- 0 the value is returned"); + static_assert(!base_helper(T(-0)), "If the arg is +- 0 the value is returned"); + static_assert(boost::math::ccmath::isinf(base_helper(std::numeric_limits::infinity())), "If the arg is +- inf the value is returned"); + static_assert(boost::math::ccmath::isinf(base_helper(-std::numeric_limits::infinity())), "If the arg is +- inf the value is returned"); + + // N[125/32, 30] + // 3.90625000000000000000000000000 + // 0.976562500000000000000000000000 * 2^2 + constexpr T test_base = base_helper(T(125.0/32)); + static_assert(test_base == T(0.9765625)); + constexpr int test_exp = exp_helper(T(125.0/32)); + static_assert(test_exp == 2); } #ifndef BOOST_MATH_NO_CONSTEXPR_DETECTION From e39d6c712b0a5ccbdad316b85ef7f68597e3ad2c Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Sep 2021 10:24:58 +0300 Subject: [PATCH 5/6] Remove testing using __builtin_constant_p --- include/boost/math/ccmath/frexp.hpp | 2 +- test/ccmath_frexp_test.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/boost/math/ccmath/frexp.hpp b/include/boost/math/ccmath/frexp.hpp index 791612a37b..88b520c1ec 100644 --- a/include/boost/math/ccmath/frexp.hpp +++ b/include/boost/math/ccmath/frexp.hpp @@ -87,7 +87,7 @@ inline constexpr float frexpf(float arg, int* exp) } #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS -inline constexpr float frexpl(long double arg, int* exp) +inline constexpr long double frexpl(long double arg, int* exp) { return boost::math::ccmath::frexp(arg, exp); } diff --git a/test/ccmath_frexp_test.cpp b/test/ccmath_frexp_test.cpp index a94bca108b..75a11b26a5 100644 --- a/test/ccmath_frexp_test.cpp +++ b/test/ccmath_frexp_test.cpp @@ -56,7 +56,7 @@ constexpr void test() static_assert(test_exp == 2); } -#ifndef BOOST_MATH_NO_CONSTEXPR_DETECTION +#if !defined(BOOST_MATH_NO_CONSTEXPR_DETECTION) && !defined(BOOST_MATH_USING_BUILTIN_CONSTANT_P) int main() { test(); @@ -66,7 +66,7 @@ int main() test(); #endif - #if defined(BOOST_HAS_FLOAT128) && !defined(BOOST_MATH_USING_BUILTIN_CONSTANT_P) + #ifdef BOOST_HAS_FLOAT128 test(); #endif From e5be8800b8df58122ef625676c253af1c8349b9e Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 Sep 2021 20:39:31 +0300 Subject: [PATCH 6/6] Change naming convention of Integers in the docs [ci skip] --- doc/sf/ccmath.qbk | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/sf/ccmath.qbk b/doc/sf/ccmath.qbk index 86abd53cbc..5f4b2f4134 100644 --- a/doc/sf/ccmath.qbk +++ b/doc/sf/ccmath.qbk @@ -12,6 +12,7 @@ LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) `Constexpr` implementations of the functionality found in ``. In a `constexpr` context the functions will use an implementation defined in boost. If the context is not `constexpr` the functionality will be directly from the STL implementation of `` used by the compiler. +All functions that take an `Integer` type and return a `double` simply cast the `Integer` argument to a `double`. All of the following functions require C++17 or greater. [heading Synopsis] @@ -30,8 +31,8 @@ All of the following functions require C++17 or greater. template inline constexpr Real sqrt(Real x); - template - inline constexpr double sqrt(Z x); + template + inline constexpr double sqrt(Integer x); template inline constexpr T abs(T x); @@ -54,8 +55,8 @@ All of the following functions require C++17 or greater. template inline constexpr Real frexp(Real arg, int* exp); - template - inline constexpr double frexp(Z arg, int* exp); + template + inline constexpr double frexp(Integer arg, int* exp); } // Namespaces