mirror of
https://github.com/boostorg/math.git
synced 2025-05-11 21:33:52 +00:00
has_denorm_now (#1029)
* initial commit * remove == std::denorm_present * remove extra ) in ccmath/next
This commit is contained in:
parent
14f4e3a21f
commit
2c74b149b0
@ -261,7 +261,7 @@ next floating-point value, but `x - u` is not necessarily the previous value. S
|
||||
value. The corner cases occur at power of 2 boundaries.
|
||||
* When the argument becomes very small, it may be that there is no floating-point value that
|
||||
represents one ULP. Whether this is the case or not depends not only on whether the hardware
|
||||
may ['sometimes] support denormals (as signalled by `std::numeric_limits<FPT>::has_denorm`), but also whether these are
|
||||
may ['sometimes] support denormals (as signalled by `boost::math::detail::has_denorm_now<FPT>()`), but also whether these are
|
||||
currently enabled at runtime (for example on SSE hardware, the DAZ or FTZ flags will disable denormal support).
|
||||
In this situation, the `ulp` function may return a value that is many orders of magnitude too large.
|
||||
|
||||
|
@ -289,7 +289,7 @@ The domain of /W/[sub -1] is \[-/e/[super -1], 0\). Numerically,
|
||||
For example, for `double`: lambert_wm1(-2.2250738585072014e-308) = -714.96865723796634 [br]
|
||||
and for `float`: lambert_wm1(-1.17549435e-38) = -91.8567734 [br]
|
||||
|
||||
* `z < -std::numeric_limits<T>::min()`, means that z is zero or denormalized (if `std::numeric_limits<T>::has_denorm_min == true`),
|
||||
* `z < -std::numeric_limits<T>::min()`, means that z is zero or denormalized (if `boost::math::detail::has_denorm_now<T>() == true`),
|
||||
for example: `r = lambert_wm1(-std::numeric_limits<double>::denorm_min());` and an overflow_error exception is thrown,
|
||||
and will give a message like:
|
||||
|
||||
|
@ -20,6 +20,8 @@
|
||||
#include <boost/math/tools/config.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/math/special_functions/next.hpp> // for has_denorm_now
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool is_big_endian()
|
||||
@ -111,9 +113,9 @@ template<class T> void print_table()
|
||||
{
|
||||
print_row("0", (T)0);
|
||||
print_row("sn.min", std::numeric_limits<T>::denorm_min(),
|
||||
std::numeric_limits<T>::has_denorm);
|
||||
boost::math::detail::has_denorm_now<T>());
|
||||
print_row("-sn.min", -std::numeric_limits<T>::denorm_min(),
|
||||
std::numeric_limits<T>::has_denorm);
|
||||
boost::math::detail::has_denorm_now<T>());
|
||||
print_row("n.min/256", (std::numeric_limits<T>::min)()/256);
|
||||
print_row("n.min/2", (std::numeric_limits<T>::min)()/2);
|
||||
print_row("-n.min/2", -(std::numeric_limits<T>::min)()/2);
|
||||
|
@ -101,7 +101,7 @@ constexpr T get_smallest_value(const std::false_type&)
|
||||
template <typename T>
|
||||
constexpr T get_smallest_value()
|
||||
{
|
||||
return get_smallest_value<T>(std::integral_constant<bool, std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == std::denorm_present)>());
|
||||
return get_smallest_value<T>(std::integral_constant<bool, std::numeric_limits<T>::is_specialized>());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
@ -55,6 +55,7 @@ BOOST_MATH_INSTRUMENT_LAMBERT_W_SMALL_Z_SERIES_ITERATIONS // Show evaluation of
|
||||
#include <boost/math/special_functions/fpclassify.hpp>
|
||||
#include <boost/math/special_functions/log1p.hpp> // for log (1 + x)
|
||||
#include <boost/math/constants/constants.hpp> // For exp_minus_one == 3.67879441171442321595523770161460867e-01.
|
||||
#include <boost/math/special_functions/next.hpp> // for has_denorm_now
|
||||
#include <boost/math/special_functions/pow.hpp> // powers with compile time exponent, used in arbitrary precision code.
|
||||
#include <boost/math/tools/series.hpp> // series functor.
|
||||
//#include <boost/math/tools/polynomial.hpp> // polynomial.
|
||||
@ -1797,7 +1798,7 @@ T lambert_wm1_imp(const T z, const Policy& pol)
|
||||
return -tools::max_value<T>();
|
||||
}
|
||||
}
|
||||
if (std::numeric_limits<T>::has_denorm)
|
||||
if (boost::math::detail::has_denorm_now<T>())
|
||||
{ // All real types except arbitrary precision.
|
||||
if (!(boost::math::isnormal)(z))
|
||||
{ // Almost zero - might also just return infinity like z == 0 or max_value?
|
||||
|
@ -82,8 +82,8 @@ inline T normalize_value(const T& val, const std::true_type&)
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T get_smallest_value(std::true_type const&)
|
||||
{
|
||||
inline T get_smallest_value(std::true_type const&) {
|
||||
static_assert(std::numeric_limits<T>::is_specialized, "Type T must be specialized.");
|
||||
//
|
||||
// numeric_limits lies about denorms being present - particularly
|
||||
// when this can be turned on or off at runtime, as is the case
|
||||
@ -106,11 +106,12 @@ inline T get_smallest_value(std::false_type const&)
|
||||
template <class T>
|
||||
inline T get_smallest_value()
|
||||
{
|
||||
#if defined(BOOST_MSVC) && (BOOST_MSVC <= 1310)
|
||||
return get_smallest_value<T>(std::integral_constant<bool, std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == 1)>());
|
||||
#else
|
||||
return get_smallest_value<T>(std::integral_constant<bool, std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == std::denorm_present)>());
|
||||
#endif
|
||||
return get_smallest_value<T>(std::integral_constant<bool, std::numeric_limits<T>::is_specialized>());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline bool has_denorm_now() {
|
||||
return get_smallest_value<T>() < tools::min_value<T>();
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <boost/limits.hpp>
|
||||
#include <boost/math/concepts/real_concept.hpp>
|
||||
#include <boost/math/special_functions/fpclassify.hpp>
|
||||
#include <boost/math/special_functions/next.hpp> // for has_denorm_now
|
||||
#define BOOST_TEST_MAIN
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <iostream>
|
||||
@ -105,7 +106,7 @@ void test_classify(T t, const char* type)
|
||||
}
|
||||
}
|
||||
}
|
||||
if(std::numeric_limits<T>::has_denorm)
|
||||
if(boost::math::detail::has_denorm_now<T>())
|
||||
{
|
||||
t = (std::numeric_limits<T>::min)();
|
||||
t /= 2;
|
||||
|
@ -90,7 +90,7 @@ void test_values(const T& val, const char* name)
|
||||
test_value(-boost::math::tools::epsilon<T>(), name);
|
||||
test_value(boost::math::tools::min_value<T>(), name);
|
||||
test_value(-boost::math::tools::min_value<T>(), name);
|
||||
if (std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == std::denorm_present) && ((std::numeric_limits<T>::min)() / 2 != 0))
|
||||
if (std::numeric_limits<T>::is_specialized && boost::math::detail::has_denorm_now<T>() && ((std::numeric_limits<T>::min)() / 2 != 0))
|
||||
{
|
||||
test_value(z, name);
|
||||
test_value(-z, name);
|
||||
|
@ -11,6 +11,7 @@
|
||||
#define BOOST_TEST_MAIN
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/test/tools/floating_point_comparison.hpp>
|
||||
#include <boost/math/special_functions/next.hpp> // for has_denorm_now
|
||||
#include <boost/math/tools/stats.hpp>
|
||||
#include <boost/math/tools/test.hpp>
|
||||
#include <boost/math/constants/constants.hpp>
|
||||
@ -319,7 +320,7 @@ void test_spots(T, const char* name)
|
||||
BOOST_CHECK(sign == -1);
|
||||
}
|
||||
|
||||
if(std::numeric_limits<T>::has_denorm && std::numeric_limits<T>::has_infinity && (boost::math::isinf)(1 / std::numeric_limits<T>::denorm_min()))
|
||||
if(boost::math::detail::has_denorm_now<T>() && std::numeric_limits<T>::has_infinity && (boost::math::isinf)(1 / std::numeric_limits<T>::denorm_min()))
|
||||
{
|
||||
BOOST_CHECK_EQUAL(boost::math::tgamma(-std::numeric_limits<T>::denorm_min()), -std::numeric_limits<T>::infinity());
|
||||
BOOST_CHECK_EQUAL(boost::math::tgamma(std::numeric_limits<T>::denorm_min()), std::numeric_limits<T>::infinity());
|
||||
@ -336,7 +337,7 @@ void test_spots(T, const char* name)
|
||||
//
|
||||
// Super small values may cause spurious overflow:
|
||||
//
|
||||
if (std::numeric_limits<T>::is_specialized && std::numeric_limits<T>::has_denorm)
|
||||
if (std::numeric_limits<T>::is_specialized && boost::math::detail::has_denorm_now<T>())
|
||||
{
|
||||
T value = (std::numeric_limits<T>::min)();
|
||||
while (value != 0)
|
||||
|
@ -8,6 +8,7 @@
|
||||
#define BOOST_TEST_MAIN
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/test/tools/floating_point_comparison.hpp>
|
||||
#include <boost/math/special_functions/next.hpp> // for has_denorm_now
|
||||
#include <boost/math/special_functions/math_fwd.hpp>
|
||||
#include <boost/math/tools/stats.hpp>
|
||||
#include <boost/math/tools/test.hpp>
|
||||
@ -305,7 +306,7 @@ void test_spots(T)
|
||||
BOOST_MATH_CHECK_THROW(::boost::math::ibeta_inv(static_cast<T>(2.125), -n, static_cast<T>(0.125)), std::domain_error);
|
||||
BOOST_MATH_CHECK_THROW(::boost::math::ibeta_inv(static_cast<T>(2.125), static_cast<T>(1.125), -n), std::domain_error);
|
||||
}
|
||||
if (std::numeric_limits<T>::has_denorm)
|
||||
if (boost::math::detail::has_denorm_now<T>())
|
||||
{
|
||||
T m = std::numeric_limits<T>::denorm_min();
|
||||
T small = 2 * (std::numeric_limits<T>::min)();
|
||||
|
@ -491,7 +491,7 @@ void test_spots(RealType)
|
||||
}
|
||||
|
||||
// denorm - but might be == min or zero?
|
||||
if (std::numeric_limits<RealType>::has_denorm == true)
|
||||
if (boost::math::detail::has_denorm_now<RealType>())
|
||||
{ // Might also return infinity like z == 0?
|
||||
BOOST_CHECK_THROW(lambert_wm1(std::numeric_limits<RealType>::denorm_min()), std::overflow_error);
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ void test_value(const T& val, const char* name)
|
||||
|
||||
BOOST_CHECK_EQUAL(float_distance(float_advance(val, 4), val), -4);
|
||||
BOOST_CHECK_EQUAL(float_distance(float_advance(val, -4), val), 4);
|
||||
if(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == std::denorm_present))
|
||||
if(std::numeric_limits<T>::is_specialized && boost::math::detail::has_denorm_now<T>())
|
||||
{
|
||||
BOOST_CHECK_EQUAL(float_distance(float_advance(float_next(float_next(val)), 4), float_next(float_next(val))), -4);
|
||||
BOOST_CHECK_EQUAL(float_distance(float_advance(float_next(float_next(val)), -4), float_next(float_next(val))), 4);
|
||||
@ -122,7 +122,7 @@ void test_values(const T& val, const char* name)
|
||||
test_value(-boost::math::tools::epsilon<T>(), name);
|
||||
test_value(boost::math::tools::min_value<T>(), name);
|
||||
test_value(-boost::math::tools::min_value<T>(), name);
|
||||
if (std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == std::denorm_present) && ((std::numeric_limits<T>::min)() / 2 != 0))
|
||||
if (std::numeric_limits<T>::is_specialized && boost::math::detail::has_denorm_now<T>() && ((std::numeric_limits<T>::min)() / 2 != 0))
|
||||
{
|
||||
test_value(z, name);
|
||||
test_value(-z, name);
|
||||
@ -135,7 +135,7 @@ void test_values(const T& val, const char* name)
|
||||
if((_mm_getcsr() & (_MM_FLUSH_ZERO_ON | 0x40)) == 0)
|
||||
{
|
||||
#endif
|
||||
if(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == std::denorm_present) && ((std::numeric_limits<T>::min)() / 2 != 0))
|
||||
if(std::numeric_limits<T>::is_specialized && boost::math::detail::has_denorm_now<T>() && ((std::numeric_limits<T>::min)() / 2 != 0))
|
||||
{
|
||||
test_value(std::numeric_limits<T>::denorm_min(), name);
|
||||
test_value(-std::numeric_limits<T>::denorm_min(), name);
|
||||
|
@ -61,7 +61,7 @@ void test_value(const T& val, const char* name)
|
||||
}
|
||||
BOOST_CHECK_EQUAL(float_distance(float_advance(val, 4), val), -4);
|
||||
BOOST_CHECK_EQUAL(float_distance(float_advance(val, -4), val), 4);
|
||||
if(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == std::denorm_present))
|
||||
if(std::numeric_limits<T>::is_specialized && boost::math::detail::has_denorm_now<T>())
|
||||
{
|
||||
BOOST_CHECK_EQUAL(float_distance(float_advance(float_next(float_next(val)), 4), float_next(float_next(val))), -4);
|
||||
BOOST_CHECK_EQUAL(float_distance(float_advance(float_next(float_next(val)), -4), float_next(float_next(val))), 4);
|
||||
@ -132,7 +132,7 @@ void test_values(const T& val, const char* name)
|
||||
test_value(T(-boost::math::tools::epsilon<T>()), name);
|
||||
test_value(boost::math::tools::min_value<T>(), name);
|
||||
test_value(T(-boost::math::tools::min_value<T>()), name);
|
||||
if (std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == std::denorm_present) && ((std::numeric_limits<T>::min)() / 2 != 0))
|
||||
if (std::numeric_limits<T>::is_specialized && boost::math::detail::has_denorm_now<T>() && ((std::numeric_limits<T>::min)() / 2 != 0))
|
||||
{
|
||||
test_value(z, name);
|
||||
test_value(T(-z), name);
|
||||
@ -142,7 +142,7 @@ void test_values(const T& val, const char* name)
|
||||
test_value(radix, name);
|
||||
test_value(T(-radix), name);
|
||||
|
||||
if(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == std::denorm_present) && ((std::numeric_limits<T>::min)() / 2 != 0))
|
||||
if(std::numeric_limits<T>::is_specialized && boost::math::detail::has_denorm_now<T>() && ((std::numeric_limits<T>::min)() / 2 != 0))
|
||||
{
|
||||
test_value(std::numeric_limits<T>::denorm_min(), name);
|
||||
test_value(T(-std::numeric_limits<T>::denorm_min()), name);
|
||||
|
@ -21,6 +21,7 @@
|
||||
#define BOOST_TEST_MAIN
|
||||
#include <boost/test/unit_test.hpp> // Boost.Test
|
||||
#include <boost/test/tools/floating_point_comparison.hpp>
|
||||
#include <boost/math/special_functions/next.hpp> // for has_denorm_now
|
||||
|
||||
#include <boost/math/concepts/real_concept.hpp> // for real_concept
|
||||
#include <boost/math/tools/test.hpp> // for real_concept
|
||||
@ -390,7 +391,7 @@ void test_spots(RealType)
|
||||
//
|
||||
// Bug cases:
|
||||
//
|
||||
if (std::numeric_limits<RealType>::is_specialized && std::numeric_limits<RealType>::has_denorm)
|
||||
if (std::numeric_limits<RealType>::is_specialized && boost::math::detail::has_denorm_now<RealType>())
|
||||
{
|
||||
BOOST_CHECK_THROW(boost::math::quantile(students_t_distribution<RealType>((std::numeric_limits<RealType>::min)() / 2), static_cast<RealType>(0.0025f)), std::overflow_error);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user