-
Notifications
You must be signed in to change notification settings - Fork 221
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
constexpr frexp #686
Merged
Merged
constexpr frexp #686
Changes from 5 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
945d456
Initial commit
mborland 8238fd8
Add include test
mborland 4eb6ca5
Add test set
mborland ff3aa3a
Fix testing methods
mborland e39d6c7
Remove testing using __builtin_constant_p
mborland e5be880
Change naming convention of Integers in the docs
mborland File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <cmath> | ||
#include <limits> | ||
#include <type_traits> | ||
#include <boost/math/ccmath/isinf.hpp> | ||
#include <boost/math/ccmath/isnan.hpp> | ||
#include <boost/math/ccmath/isfinite.hpp> | ||
|
||
namespace boost::math::ccmath { | ||
|
||
namespace detail | ||
{ | ||
|
||
template <typename Real> | ||
inline constexpr Real frexp_zero_impl(Real arg, int* exp) | ||
{ | ||
*exp = 0; | ||
return arg; | ||
} | ||
|
||
template <typename Real> | ||
inline constexpr Real frexp_impl(Real arg, int* exp) | ||
{ | ||
const 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 <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true> | ||
inline constexpr Real frexp(Real arg, int* exp) | ||
{ | ||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(arg)) | ||
{ | ||
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); | ||
} | ||
} | ||
|
||
template <typename Z, std::enable_if_t<std::is_integral_v<Z>, bool> = true> | ||
inline constexpr double frexp(Z arg, int* exp) | ||
{ | ||
return boost::math::ccmath::frexp(static_cast<double>(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 long double frexpl(long double arg, int* exp) | ||
{ | ||
return boost::math::ccmath::frexp(arg, exp); | ||
} | ||
#endif | ||
|
||
} | ||
|
||
#endif // BOOST_MATH_CCMATH_FREXP_HPP |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// (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 <cmath> | ||
#include <cfloat> | ||
#include <cstdint> | ||
#include <limits> | ||
#include <type_traits> | ||
#include <boost/math/ccmath/frexp.hpp> | ||
#include <boost/math/ccmath/isnan.hpp> | ||
#include <boost/math/ccmath/isinf.hpp> | ||
|
||
#ifdef BOOST_HAS_FLOAT128 | ||
#include <boost/multiprecision/float128.hpp> | ||
#endif | ||
|
||
template <typename T> | ||
inline constexpr T base_helper(const T val) | ||
{ | ||
int i = 0; | ||
const T ans = boost::math::ccmath::frexp(val, &i); | ||
|
||
return ans; | ||
} | ||
|
||
template <typename T> | ||
inline constexpr int exp_helper(const T val) | ||
{ | ||
int i = 0; | ||
boost::math::ccmath::frexp(val, &i); | ||
|
||
return i; | ||
} | ||
|
||
template <typename T> | ||
constexpr void test() | ||
{ | ||
if constexpr (std::numeric_limits<T>::has_quiet_NaN) | ||
{ | ||
static_assert(boost::math::ccmath::isnan(base_helper(std::numeric_limits<T>::quiet_NaN())), "If the arg is NaN, NaN is returned"); | ||
} | ||
|
||
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<T>::infinity())), "If the arg is +- inf the value is returned"); | ||
static_assert(boost::math::ccmath::isinf(base_helper(-std::numeric_limits<T>::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); | ||
} | ||
|
||
#if !defined(BOOST_MATH_NO_CONSTEXPR_DETECTION) && !defined(BOOST_MATH_USING_BUILTIN_CONSTANT_P) | ||
int main() | ||
{ | ||
test<float>(); | ||
test<double>(); | ||
|
||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS | ||
test<long double>(); | ||
#endif | ||
|
||
#ifdef BOOST_HAS_FLOAT128 | ||
test<boost::multiprecision::float128>(); | ||
#endif | ||
|
||
return 0; | ||
} | ||
#else | ||
int main() | ||
{ | ||
return 0; | ||
} | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <boost/math/ccmath/frexp.hpp> | ||
#include "test_compile_result.hpp" | ||
|
||
void compile_and_link_test() | ||
{ | ||
int i; | ||
check_result<float>(boost::math::ccmath::frexp(1.0f, &i)); | ||
check_result<double>(boost::math::ccmath::frexp(1.0, &i)); | ||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS | ||
check_result<long double>(boost::math::ccmath::frexp(1.0l, &i)); | ||
#endif | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trivial quibble, but I when I first read this I didn't grok that this was limited to integer arguments, maybe use
<typename Integer>
and perhaps a comment that this is for integer arguments?Other than that, I'm happy for this to be merged, and you'll be pleased to know that ldexp should be noticeably easier! :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jzmaddock : That was my (perhaps poor) convention; mimicking ℤ.
Is it possible to do a concept without breaking C++17 compatibility?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really, although the enable_if does much the same thing. It's debatable whether the enable_if condition should be part of the declared interface - it clutters up the docs, but does at least make it clear what the requirements on Z are.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doc suggestions have been incorporated in the latest commit.
As for concepts, you can avoid breaking C++17 compatibility using this macro (taken from good concepts):