diff --git a/README.md b/README.md
index 2c0882963..38f5c5f3c 100644
--- a/README.md
+++ b/README.md
@@ -3,13 +3,14 @@ Boost Multiprecision Library
| | Master | Develop |
|------------------|----------|-------------|
-| Drone | [](https://drone.cpp.al/boostorg/multiprecision) | [](https://drone.cpp.al/boostorg/multiprecision) |
-| Github Actions | [](https://github.com/boostorg/multiprecision/actions) | [](https://github.com/boostorg/multiprecision/actions) |
-| Codecov | [](https://codecov.io/gh/boostorg/multiprecision/branch/master) | [](https://codecov.io/gh/boostorg/multiprecision/branch/develop) |
+| Drone | [](https://drone.cpp.al/boostorg/multiprecision) | [](https://drone.cpp.al/boostorg/multiprecision) |
+| Github Actions | [](https://github.com/boostorg/multiprecision/actions) | [](https://github.com/boostorg/multiprecision/actions) |
+| Codecov | [](https://codecov.io/gh/boostorg/multiprecision/branch/master) | [](https://codecov.io/gh/boostorg/multiprecision/branch/develop) |
-`Boost.Multiprecision` is a C++ library that provides integer, rational, floating-point, complex and interval number types
-having more range and precision than the language's ordinary built-in types.
+`Boost.Multiprecision` is a C++ library that provides integer, rational, floating-point,
+complex and interval number types having more range and precision than the language's
+ordinary built-in types.
Language adherence:
- `Boost.Multiprecision` requires a compliant C++14 compiler.
@@ -21,7 +22,7 @@ also interoperate with the built-in types in C++ using clearly defined conversio
used for all kinds of mathematical calculations involving integer, rational and floating-point types requiring extended range and precision.
Multiprecision consists of a generic interface to the mathematics of large numbers as well as a selection of big number back ends, with
-support for integer, rational and floating-point types. `Boost.Multiprecision` provides a selection of back ends provided off-the-rack in
+support for integer, rational and floating-point types. `Boost.Multiprecision` provides a selection of back ends provided off-the-rack
including interfaces to GMP, MPFR, MPIR, TomMath as well as its own collection of Boost-licensed, header-only back ends for integers,
rationals, floats and complex. In addition, user-defined back ends can be created and used with the interface of Multiprecision,
provided the class implementation adheres to the necessary concepts.
@@ -29,40 +30,42 @@ provided the class implementation adheres to the necessary concepts.
Depending upon the number type, precision may be arbitrarily large (limited only by available memory), fixed at compile time
(for example $50$ or $100$ decimal digits), or a variable controlled at run-time by member functions.
The types are expression-template-enabled by default. This usually provides better performance than naive user-defined types.
-If not needed, expression templates can be disabled when configuring the `number` type with its backend.
+If not needed, expression templates can be disabled when configuring the `number`-type with its backend.
The full documentation is available on [boost.org](http://www.boost.org/doc/libs/release/libs/multiprecision/index.html).
-## Using Multiprecision ##
+## Using Multiprecision
-
+
In the following example, we use Multiprecision's Boost-licensed binary
floating-point backend type `cpp_bin_float` to compute ${\sim}100$ decimal digits of
-$$\sqrt{\pi} = \Gamma \left( \frac{1}{2} \right)~{\approx}~1.772453850905516027298{\ldots}\text{,}$$
+$$
+\sqrt{\pi} = \Gamma \left( \frac{1}{2} \right)~{\approx}~1.772453850905516027298{\ldots}\text{,}
+$$
where we also observe that Multiprecision can seemlesly interoperate with
[Boost.Math](https://github.com/boostorg/math).
```cpp
+#include
+#include
+
#include
#include
#include
-#include
-#include
-
auto main() -> int
{
using big_float_type = boost::multiprecision::cpp_bin_float_100;
const big_float_type sqrt_pi { sqrt(boost::math::constants::pi()) };
- const big_float_type half { big_float_type(1) / 2 };
+ const big_float_type half { big_float_type { 1 } / 2 };
const big_float_type gamma_half { boost::math::tgamma(half) };
@@ -75,7 +78,7 @@ auto main() -> int
}
```
-## Standalone ##
+## Standalone
Defining `BOOST_MP_STANDALONE` allows `Boost.Multiprecision`
to be used with the only dependency being [Boost.Config](https://github.com/boostorg/config).
@@ -83,11 +86,11 @@ to be used with the only dependency being [Boost.Config](https://github.com/boos
Our [package on this page](https://github.com/boostorg/multiprecision/releases)
already includes a copy of Boost.Config so no other downloads are required.
Some functionality is reduced in this mode.
-A static_assert message will alert you if a particular feature has been disabled by standalone mode.
+A `static_assert` message will alert you if a particular feature has been disabled by standalone mode.
[Boost.Math](https://github.com/boostorg/math) standalone mode is compatiable,
-and recommended if special functions are required for the floating point types.
+and recommended if special functions are required for the floating-point types.
-## Support, bugs and feature requests ##
+## Support, bugs and feature requests
Bugs and feature requests can be reported through the [Gitub issue tracker](https://github.com/boostorg/multiprecision/issues)
(see [open issues](https://github.com/boostorg/multiprecision/issues) and
@@ -100,7 +103,7 @@ although you can use the general-purpose Boost [mailing-list](http://lists.boost
using the tag [multiprecision].
-## Development ##
+## Development
Clone the whole boost project, which includes the individual Boost projects as submodules
([see boost+git doc](https://github.com/boostorg/boost/wiki/Getting-Started)):
@@ -113,7 +116,8 @@ Clone the whole boost project, which includes the individual Boost projects as s
The Boost Multiprecision Library is located in `libs/multiprecision/`.
-### Running tests ###
+### Running tests
+
First, build the `b2` engine by running `bootstrap.sh` in the root of the boost directory. This will generate `b2` configuration in `project-config.jam`.
```sh
diff --git a/doc/multiprecision.qbk b/doc/multiprecision.qbk
index 6a5072272..a8e9c2873 100644
--- a/doc/multiprecision.qbk
+++ b/doc/multiprecision.qbk
@@ -1,8 +1,8 @@
[/
- Copyright 2011 - 2024 John Maddock.
+ Copyright 2011 - 2025 John Maddock.
Copyright 2013 - 2019 Paul A. Bristow.
- Copyright 2013 - 2024 Christopher Kormanyos.
- Copyright 2021 - 2024 Fahad Syed.
+ Copyright 2013 - 2025 Christopher Kormanyos.
+ Copyright 2021 - 2025 Fahad Syed.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
@@ -11,7 +11,7 @@
[library Boost.Multiprecision
[quickbook 1.7]
- [copyright 2002-2020 John Maddock and Christopher Kormanyos]
+ [copyright 2002-2025 John Maddock and Christopher Kormanyos]
[purpose Multiprecision Number library]
[license
Distributed under the Boost Software License, Version 1.0.
diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail.hpp
index 67f8657a8..337f7f51e 100644
--- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail.hpp
+++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail.hpp
@@ -1,6 +1,6 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2021 Fahad Syed.
-// Copyright 2021 - 2024 Christopher Kormanyos.
+// Copyright 2021 - 2025 Christopher Kormanyos.
// Copyright 2021 Janek Kozicki.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath.hpp
index 74f893a1f..e5e05e56c 100644
--- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath.hpp
+++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath.hpp
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////
-// Copyright Christopher Kormanyos 2023.
+// Copyright Christopher Kormanyos 2023 - 2025.
// Distributed under 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)
diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fabs.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fabs.hpp
index 8785efa16..83dcedb8f 100644
--- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fabs.hpp
+++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fabs.hpp
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////
-// Copyright Christopher Kormanyos 2023 - 2024.
+// Copyright Christopher Kormanyos 2023 - 2025.
// Distributed under 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)
diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_floor.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_floor.hpp
index ae8bfbc8d..4df2f46a3 100644
--- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_floor.hpp
+++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_floor.hpp
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////
-// Copyright Christopher Kormanyos 2024.
+// Copyright Christopher Kormanyos 2024 - 2025.
// Distributed under 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)
diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fma.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fma.hpp
index c9100f9f8..75bee6004 100644
--- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fma.hpp
+++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fma.hpp
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////
-// Copyright Christopher Kormanyos 2024.
+// Copyright Christopher Kormanyos 2024 - 2025.
// Distributed under 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)
diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fpclassify.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fpclassify.hpp
index 3de62126c..7824e99ad 100644
--- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fpclassify.hpp
+++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fpclassify.hpp
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////
-// Copyright Christopher Kormanyos 2024.
+// Copyright Christopher Kormanyos 2024 - 2025.
// Distributed under 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)
diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_frexp.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_frexp.hpp
index 3a5f89c8e..2ca53f32c 100644
--- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_frexp.hpp
+++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_frexp.hpp
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////
-// Copyright Christopher Kormanyos 2023 - 2024.
+// Copyright Christopher Kormanyos 2023 - 2025.
// Distributed under 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)
diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_isinf.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_isinf.hpp
index 680de5397..7362c7f06 100644
--- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_isinf.hpp
+++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_isinf.hpp
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////
-// Copyright Christopher Kormanyos 2023 - 2024.
+// Copyright Christopher Kormanyos 2023 - 2025.
// Distributed under 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)
diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_isnan.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_isnan.hpp
index 63fc3b468..468a97b97 100644
--- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_isnan.hpp
+++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_isnan.hpp
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////
-// Copyright Christopher Kormanyos 2023 - 2024.
+// Copyright Christopher Kormanyos 2023 - 2025.
// Distributed under 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)
diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_ldexp.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_ldexp.hpp
index f9535d647..da2510969 100644
--- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_ldexp.hpp
+++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_ldexp.hpp
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////
-// Copyright Christopher Kormanyos 2023 - 2024.
+// Copyright Christopher Kormanyos 2023 - 2025.
// Distributed under 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)
diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_limits.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_limits.hpp
index 9b3e2d272..7d8b01c1f 100644
--- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_limits.hpp
+++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_limits.hpp
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////
-// Copyright Christopher Kormanyos 2023 - 2024.
+// Copyright Christopher Kormanyos 2023 - 2025.
// Distributed under 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)
diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_log.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_log.hpp
index b9a8f42d9..64cd301ed 100644
--- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_log.hpp
+++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_log.hpp
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////
-// Copyright Christopher Kormanyos 2024.
+// Copyright Christopher Kormanyos 2024 - 2025.
// Distributed under 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)
diff --git a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_sqrt.hpp b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_sqrt.hpp
index ba985d790..381570b91 100644
--- a/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_sqrt.hpp
+++ b/include/boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_sqrt.hpp
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////
-// Copyright Christopher Kormanyos 2023 - 2024.
+// Copyright Christopher Kormanyos 2023 - 2025.
// Distributed under 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)
diff --git a/include/boost/multiprecision/cpp_double_fp.hpp b/include/boost/multiprecision/cpp_double_fp.hpp
index 4b94b9e42..704953050 100644
--- a/include/boost/multiprecision/cpp_double_fp.hpp
+++ b/include/boost/multiprecision/cpp_double_fp.hpp
@@ -1,6 +1,6 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2021 Fahad Syed.
-// Copyright 2021 - 2024 Christopher Kormanyos.
+// Copyright 2021 - 2025 Christopher Kormanyos.
// Copyright 2021 Janek Kozicki.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
@@ -122,12 +122,6 @@ template
constexpr typename ::std::enable_if::value>::type eval_convert_to(OtherFloatingPointType* result, const cpp_double_fp_backend& backend);
-template
-::std::basic_ostream& operator<<(std::basic_ostream& os,
- const cpp_double_fp_backend& f);
-
template
::std::size_t hash_value(const cpp_double_fp_backend& a);
@@ -356,20 +350,36 @@ class cpp_double_fp_backend
std::size_t hash() const
{
- // Here we first convert to scientific string, then
- // hash the charactgers in the scientific string.
+ // Hash the raw values of the data field with direct-memory access.
+ // Use 16-bit (2 byte) chunks as the data size when hashing.
+
+ static_assert( ( sizeof(data.first) == sizeof(data.second))
+ && ( sizeof(float_type) >= sizeof(std::uint16_t))
+ && ((sizeof(float_type) % sizeof(std::uint16_t)) == std::size_t { UINT8_C(0) }),
+ "Error: float_type size is inappropriate for hashing routine");
+
+ auto hash_one
+ {
+ [](std::size_t& res, const float_type& val)
+ {
+ const std::uint16_t* first { reinterpret_cast(&val) };
+ const std::uint16_t* last { first + std::size_t { sizeof(float_type) / sizeof(std::uint16_t) } };
+
+ while (first != last)
+ {
+ boost::multiprecision::detail::hash_combine(res, *first);
- // TBD: Is there a faster or more simple hash method?
- // TBD: Is there any constexpr support for rudimentary hashing?
+ ++first;
+ }
- const std::string str_to_hash { str(cpp_double_fp_backend::my_digits10, std::ios::scientific) };
+ return res;
+ }
+ };
std::size_t result { UINT8_C(0) };
- for (std::size_t i = std::size_t { UINT8_C(0) }; i < str_to_hash.length(); ++i)
- {
- boost::multiprecision::detail::hash_combine(result, str_to_hash.at(i));
- }
+ static_cast(hash_one(result, data.first));
+ static_cast(hash_one(result, data.second));
return result;
}
@@ -572,13 +582,7 @@ class cpp_double_fp_backend
if (iszero_u || iszero_v)
{
- const bool b_neg { (isneg_unchecked() != v.isneg_unchecked()) };
-
- operator=(cpp_double_fp_backend(0));
-
- if (b_neg) { negate(); }
-
- return *this;
+ return operator=(cpp_double_fp_backend(0));
}
}
@@ -678,14 +682,6 @@ class cpp_double_fp_backend
const bool iszero_u { (fpc_u == FP_ZERO) };
const bool iszero_v { (fpc_v == FP_ZERO) };
- if (this == &v)
- {
- data.first = float_type { 1.0F };
- data.second = float_type { 0.0F };
-
- return *this;
- }
-
if (iszero_u)
{
if (iszero_v)
@@ -736,6 +732,14 @@ class cpp_double_fp_backend
}
}
+ if (this == &v)
+ {
+ data.first = float_type { 1.0F };
+ data.second = float_type { 0.0F };
+
+ return *this;
+ }
+
// The division algorithm has been taken from Victor Shoup,
// package WinNTL-5_3_2. It might originally be related to the
// K. Briggs work. The algorithm has been significantly simplified
@@ -840,56 +844,6 @@ class cpp_double_fp_backend
return v;
}
- // Helper functions.
- constexpr static cpp_double_fp_backend pown(const cpp_double_fp_backend& x, int p)
- {
- using local_float_type = cpp_double_fp_backend;
-
- local_float_type result { };
-
- if (p < 0)
- result = pown(local_float_type(1U) / x, -p);
- else if (p == 0)
- result = local_float_type(1U);
- else if (p == 1)
- result = x;
- else if (p == 2)
- result = local_float_type(x * x);
- else if (p == 3)
- result = local_float_type((x * x) * x);
- else if (p == 4)
- { const local_float_type x2 { x * x }; result = x2 * x2; }
- else
- {
- result = local_float_type(1U);
-
- local_float_type y(x);
-
- auto p_local = static_cast(p);
-
- for (;;)
- {
- if (static_cast(p_local & static_cast(UINT8_C(1))) != static_cast(UINT8_C(0)))
- {
- result *= y;
- }
-
- p_local >>= 1U;
-
- if (p_local == static_cast(UINT8_C(0)))
- {
- break;
- }
- else
- {
- y *= y;
- }
- }
- }
-
- return result;
- }
-
constexpr void swap(cpp_double_fp_backend& other)
{
if (this != &other)
@@ -953,56 +907,37 @@ class cpp_double_fp_backend
return e2;
}
- constexpr int order10() const { return static_cast(static_cast(order02()) * 0.301F); }
-
- constexpr bool small_arg() const { return (order10() < static_cast(-my_digits10 / 6)); }
-
- constexpr bool near_one() const
- {
- cpp_double_fp_backend delta_one { };
-
- eval_subtract(delta_one, cpp_double_fp_backend(1U), *this);
-
- if (delta_one().isneg_unchecked())
- {
- delta_one.negate();
- }
-
- return delta_one.small_arg();
- }
-
static constexpr cpp_double_fp_backend my_value_max() noexcept
{
// Use the non-normalized sum of two maximum values, where the lower
// value is "shifted" right in the sense of floating-point ldexp.
- // TBD: This value _still_ needs to be independently verified.
+ constexpr float_type
+ hi_part
+ {
+ (cpp_df_qf_detail::ccmath::numeric_limits::max)()
+ * (
+ static_cast(1.0F)
+ - static_cast(1.5F) * cpp_df_qf_detail::ccmath::unsafe::sqrt(cpp_df_qf_detail::ccmath::numeric_limits::epsilon())
+ )
+ };
- constexpr cpp_double_fp_backend
- my_value_max_constexpr
+ constexpr float_type
+ lo_part
{
- arithmetic::two_hilo_sum
+ cpp_df_qf_detail::ccmath::unsafe::ldexp
(
- static_cast
- (
- (cpp_df_qf_detail::ccmath::numeric_limits::max)()
- * (
- static_cast(1.0F)
- - static_cast(1.5F) * cpp_df_qf_detail::ccmath::unsafe::sqrt(cpp_df_qf_detail::ccmath::numeric_limits::epsilon())
- )
- ),
- cpp_df_qf_detail::ccmath::unsafe::ldexp
- (
- (cpp_df_qf_detail::ccmath::numeric_limits::max)(),
- -(cpp_df_qf_detail::ccmath::numeric_limits::digits + 1)
- )
+ (cpp_df_qf_detail::ccmath::numeric_limits::max)(),
+ -cpp_df_qf_detail::ccmath::numeric_limits::digits
)
};
+ constexpr cpp_double_fp_backend my_value_max_constexpr { arithmetic::two_hilo_sum(hi_part, lo_part) };
+
static_assert
(
- eval_gt(my_value_max_constexpr, cpp_double_fp_backend { (cpp_df_qf_detail::ccmath::numeric_limits::max)() / 2 }),
- "Error: maximum value is too small and must exceed (1/2 * max) of its constituent type"
+ eval_gt(my_value_max_constexpr, cpp_double_fp_backend { hi_part }),
+ "Error: maximum value is too small in relation to the maximum of its constituent type"
);
return my_value_max_constexpr;
@@ -1019,7 +954,7 @@ class cpp_double_fp_backend
cpp_df_qf_detail::ccmath::unsafe::ldexp
(
(cpp_df_qf_detail::ccmath::numeric_limits::min)(),
- cpp_df_qf_detail::ccmath::numeric_limits::digits
+ cpp_df_qf_detail::ccmath::numeric_limits::digits
)
};
@@ -1270,29 +1205,6 @@ constexpr cpp_double_fp_backend operator*(const cpp_double_fp
template
constexpr cpp_double_fp_backend operator/(const cpp_double_fp_backend& a, const cpp_double_fp_backend& b) { return cpp_double_fp_backend(a) /= b; }
-// Input/Output Streaming
-template
-::std::basic_ostream&
-operator<<(::std::basic_ostream& os, const cpp_double_fp_backend& f)
-{
- const auto str_result = f.str(os.precision(), os.flags());
-
- return (os << str_result);
-}
-
-template
-::std::basic_istream&
-operator>>(::std::basic_istream& is, cpp_double_fp_backend& f)
-{
- std::string input_str;
-
- is >> input_str;
-
- f = input_str.c_str();
-
- return is;
-}
-
template
constexpr void eval_add(cpp_double_fp_backend& result, const cpp_double_fp_backend& x) { result += x; }
template
@@ -1488,8 +1400,6 @@ constexpr void eval_exp(cpp_double_fp_backend& result, const
{
const int fpc { eval_fpclassify(x) };
- const bool x_is_zero { fpc == FP_ZERO };
-
using double_float_type = cpp_double_fp_backend;
if (fpc == FP_ZERO)
@@ -1543,11 +1453,7 @@ constexpr void eval_exp(cpp_double_fp_backend& result, const
}()
};
- if (x_is_zero)
- {
- result = double_float_type(1U);
- }
- else if (eval_lt(x, min_exp_input))
+ if (eval_lt(x, min_exp_input))
{
result = double_float_type(0U);
}
@@ -1642,8 +1548,6 @@ constexpr void eval_exp(cpp_double_fp_backend& result, const
{
const int fpc { eval_fpclassify(x) };
- const bool x_is_zero { fpc == FP_ZERO };
-
using double_float_type = cpp_double_fp_backend;
if (fpc == FP_ZERO)
@@ -1697,11 +1601,7 @@ constexpr void eval_exp(cpp_double_fp_backend& result, const
}()
};
- if (x_is_zero)
- {
- result = double_float_type(1U);
- }
- else if (eval_lt(x, min_exp_input))
+ if (eval_lt(x, min_exp_input))
{
result = double_float_type(0U);
}
@@ -1796,8 +1696,6 @@ constexpr void eval_exp(cpp_double_fp_backend& result, const
{
const int fpc { eval_fpclassify(x) };
- const bool x_is_zero { fpc == FP_ZERO };
-
using double_float_type = cpp_double_fp_backend;
if (fpc == FP_ZERO)
@@ -1851,11 +1749,7 @@ constexpr void eval_exp(cpp_double_fp_backend& result, const
}()
};
- if (x_is_zero)
- {
- result = double_float_type(1U);
- }
- else if (eval_lt(x, min_exp_input))
+ if (eval_lt(x, min_exp_input))
{
result = double_float_type(0U);
}
@@ -2022,19 +1916,23 @@ constexpr void eval_convert_to(signed long long* result, const cpp_double_fp_bac
return;
}
- constexpr signed long long my_max_val = (std::numeric_limits::max)();
- constexpr signed long long my_min_val = (std::numeric_limits::min)();
+ constexpr signed long long my_max_val { (std::numeric_limits::max)() };
+ constexpr signed long long my_min_val { (std::numeric_limits::min)() };
using c_type = typename std::common_type::type;
- constexpr c_type my_max = static_cast(my_max_val);
- const c_type ct = cpp_df_qf_detail::ccmath::fabs(backend.crep().first);
+ constexpr c_type my_max { static_cast(my_max_val) };
+ constexpr c_type my_min { static_cast(my_min_val) };
+
+ const c_type ct { static_cast(backend.crep().first) };
if (ct > my_max)
{
- *result = backend.crep().first >= typename cpp_double_fp_backend::float_type(0U)
- ? my_max_val
- : my_min_val;
+ *result = my_max_val;
+ }
+ else if (ct < my_min)
+ {
+ *result = my_min_val;
}
else
{
@@ -2075,12 +1973,13 @@ constexpr void eval_convert_to(unsigned long long* result, const cpp_double_fp_b
return;
}
- constexpr unsigned long long my_max_val = (std::numeric_limits::max)();
+ constexpr unsigned long long my_max_val { (std::numeric_limits::max)() };
using c_type = typename std::common_type::type;
- constexpr c_type my_max = static_cast(my_max_val);
- const c_type ct = cpp_df_qf_detail::ccmath::fabs(backend.crep().first);
+ constexpr c_type my_max { static_cast(my_max_val) };
+
+ const c_type ct { static_cast(backend.crep().first) };
if (ct > my_max)
{
@@ -2088,112 +1987,73 @@ constexpr void eval_convert_to(unsigned long long* result, const cpp_double_fp_b
}
else
{
- BOOST_IF_CONSTEXPR(std::numeric_limits::digits >= cpp_df_qf_detail::ccmath::numeric_limits::digits)
- {
- *result = static_cast(backend.crep().first);
- *result += static_cast(backend.crep().second);
- }
- else
- {
- cpp_double_fp_backend source = backend;
-
- *result = 0;
-
- for(auto digit_count = 0;
- digit_count < cpp_double_fp_backend::my_digits;
- digit_count += std::numeric_limits::digits)
- {
- const auto next = static_cast(source.crep().first);
-
- *result += next;
-
- eval_subtract(source, cpp_double_fp_backend(next));
- }
- }
+ *result = static_cast(backend.crep().first);
+ *result += static_cast(backend.crep().second);
}
}
#ifdef BOOST_HAS_INT128
template
-constexpr void eval_convert_to(int128_type* result, const cpp_double_fp_backend& backend)
+constexpr void eval_convert_to(boost::int128_type* result, const cpp_double_fp_backend& backend)
{
const auto fpc = eval_fpclassify(backend);
if (fpc != FP_NORMAL)
{
- *result = static_cast(backend.crep().first);
+ *result = static_cast(backend.crep().first);
return;
}
- constexpr int128_type my_max_val = (((static_cast(1) << (sizeof(int128_type) * CHAR_BIT - 2)) - 1) << 1) + 1;
- constexpr int128_type my_min_val = static_cast(-my_max_val - 1);
+ constexpr boost::int128_type my_max_val = (((static_cast(1) << (sizeof(boost::int128_type) * CHAR_BIT - 2)) - 1) << 1) + 1;
+ constexpr boost::int128_type my_min_val = static_cast(-my_max_val - 1);
- using c_type = typename std::common_type::type;
+ using c_type = typename std::common_type::type;
- constexpr c_type my_max = static_cast(my_max_val);
- const c_type ct = cpp_df_qf_detail::ccmath::fabs(backend.crep().first);
+ constexpr c_type my_max { static_cast(my_max_val) };
+ constexpr c_type my_min { static_cast(my_min_val) };
+
+ const c_type ct { static_cast(backend.crep().first) };
if (ct > my_max)
{
- *result = backend.crep().first >= typename cpp_double_fp_backend::float_type(0U)
- ? my_max_val
- : my_min_val;
+ *result = my_max_val;
+ }
+ if (ct < my_min)
+ {
+ *result = my_min_val;
}
else
{
- BOOST_IF_CONSTEXPR(static_cast(static_cast(sizeof(int128_type)) * CHAR_BIT) >= cpp_df_qf_detail::ccmath::numeric_limits::digits)
- {
- *result = static_cast(backend.crep().first);
- *result += static_cast(backend.crep().second);
- }
- else
- {
- cpp_double_fp_backend source = backend;
-
- *result = 0;
-
- for(auto digit_count = static_cast(0);
- digit_count < cpp_double_fp_backend::my_digits;
- digit_count += static_cast(static_cast(sizeof(int128_type)) * CHAR_BIT))
- {
- const auto next = static_cast(source.crep().first);
-
- *result += next;
-
- eval_subtract(source, cpp_double_fp_backend(next));
- }
- }
+ *result = static_cast(backend.crep().first);
+ *result += static_cast(backend.crep().second);
}
}
template
-constexpr void eval_convert_to(uint128_type* result, const cpp_double_fp_backend& backend)
+constexpr void eval_convert_to(boost::uint128_type* result, const cpp_double_fp_backend& backend)
{
const auto fpc = eval_fpclassify(backend);
if (fpc != FP_NORMAL)
{
- *result = static_cast(backend.crep().first);
+ *result = static_cast(backend.crep().first);
return;
}
- uint128_type my_max_val { };
-
- BOOST_IF_CONSTEXPR(std::is_same::value && (std::numeric_limits::digits == 24))
+ constexpr boost::uint128_type my_max_val
{
- my_max_val = static_cast(FLT_MAX);
- }
- else
- {
- my_max_val = static_cast(~static_cast(0));
- }
+ (std::is_same::value && (cpp_df_qf_detail::ccmath::numeric_limits::digits == 24))
+ ? static_cast(FLT_MAX)
+ : static_cast(~static_cast(0))
+ };
+
+ using c_type = typename std::common_type::type;
- using c_type = typename std::common_type::type;
+ constexpr c_type my_max { static_cast(my_max_val) };
- const c_type my_max = static_cast(my_max_val);
- const c_type ct = cpp_df_qf_detail::ccmath::fabs(backend.crep().first);
+ const c_type ct { static_cast(backend.crep().first) };
if (ct > my_max)
{
@@ -2201,28 +2061,10 @@ constexpr void eval_convert_to(uint128_type* result, const cpp_double_fp_backend
}
else
{
- BOOST_IF_CONSTEXPR(static_cast(static_cast(sizeof(uint128_type)) * CHAR_BIT) >= cpp_df_qf_detail::ccmath::numeric_limits::digits)
- {
- *result = static_cast(backend.crep().first);
- *result += static_cast(backend.crep().second);
- }
- else
- {
- cpp_double_fp_backend source = backend;
-
- *result = 0;
+ *result = static_cast(backend.crep().first);
+ *result += static_cast(backend.crep().second);
- for(auto digit_count = static_cast(0);
- digit_count < cpp_double_fp_backend::my_digits;
- digit_count += static_cast(static_cast(sizeof(uint128_type)) * CHAR_BIT))
- {
- const auto next = static_cast(source.crep().first);
-
- *result += next;
-
- eval_subtract(source, cpp_double_fp_backend(next));
- }
- }
+ *result = static_cast(*result);
}
}
#endif
@@ -2233,7 +2075,7 @@ constexpr typename ::std::enable_ifquadmath ] ]
[ run test_cpp_dec_float_round.cpp no_eh_support ]
+ [ run test_various_edges.cpp no_eh_support ]
[ run test_arithmetic_logged_1.cpp no_eh_support : : : msvc:-bigobj [ check-target-builds ../config//has_float128 : quadmath ] ]
[ run test_arithmetic_logged_2.cpp no_eh_support : : : msvc:-bigobj [ check-target-builds ../config//has_float128 : quadmath ] ]
diff --git a/test/test_arithmetic.hpp b/test/test_arithmetic.hpp
index 6bc741aa9..6b25b4cf6 100644
--- a/test/test_arithmetic.hpp
+++ b/test/test_arithmetic.hpp
@@ -1736,6 +1736,25 @@ void test_float_ops(const std::integral_constant::is_specialized && std::numeric_limits::has_infinity && std::numeric_limits::max_exponent10 > 18 && std::numeric_limits::min_exponent10 < -18)
+ {
+ Real a = (std::numeric_limits::max)();
+
+ a /= 1000000;
+ a /= 1000000;
+ a /= 1000000;
+
+ BOOST_CHECK((boost::math::isfinite)(a));
+
+ a = (std::numeric_limits::min)();
+
+ a *= 1000000;
+ a *= 1000000;
+ a *= 1000000;
+
+ BOOST_CHECK((boost::math::isfinite)(a));
+ }
+
test_float_funcs(std::integral_constant::is_specialized>());
}
diff --git a/test/test_exp.cpp b/test/test_exp.cpp
index 11328b319..ea6394859 100644
--- a/test/test_exp.cpp
+++ b/test/test_exp.cpp
@@ -15,9 +15,12 @@
#endif
#include
-#include
#include "test.hpp"
+#include
+#include
+#include
+
#if !defined(TEST_MPF_50) && !defined(TEST_MPF) && !defined(TEST_BACKEND) && !defined(TEST_CPP_DEC_FLOAT) && !defined(TEST_MPFR) && !defined(TEST_MPFR_50) && !defined(TEST_MPFI_50) && !defined(TEST_FLOAT128) && !defined(TEST_CPP_BIN_FLOAT) && !defined(TEST_CPP_DOUBLE_FLOAT)
#define TEST_MPF_50
//# define TEST_MPF
@@ -210,7 +213,6 @@ void test()
}
}
-
#if defined(TEST_CPP_DOUBLE_FLOAT)
// Handle uneven/asymmetric exponents on min/max of cpp_double_fp_backend
bug_case = log(1 / (std::numeric_limits::min)()) / -1.0005;
diff --git a/test/test_various_edges.cpp b/test/test_various_edges.cpp
new file mode 100644
index 000000000..60cf1d659
--- /dev/null
+++ b/test/test_various_edges.cpp
@@ -0,0 +1,895 @@
+// Copyright 2023 - 2024 Matt Borland
+// Copyright 2023 - 2025 Christopher Kormanyos
+// Distributed under the Boost Software License, Version 1.0.
+// https://www.boost.org/LICENSE_1_0.txt
+
+// Some parts of this test file have been taken from the Boost.Decimal project.
+
+#if !defined(TEST_CPP_DOUBLE_FLOAT)
+#define TEST_CPP_DOUBLE_FLOAT
+#endif
+
+#include
+#include
+#if defined(TEST_CPP_DOUBLE_FLOAT)
+#include
+#endif
+
+#include
+#include
+#include
+#include
+#include
+
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wfloat-equal"
+#elif defined(__GNUC__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+
+#include
+
+template auto my_zero() noexcept -> FloatType&;
+template auto my_one () noexcept -> FloatType&;
+template auto my_inf () noexcept -> FloatType&;
+template auto my_nan () noexcept -> FloatType&;
+template auto my_exp1() noexcept -> FloatType&;
+
+namespace local
+{
+ template
+ auto time_point() noexcept -> IntegralTimePointType
+ {
+ using local_integral_time_point_type = IntegralTimePointType;
+ using local_clock_type = ClockType;
+
+ const auto current_now =
+ static_cast
+ (
+ std::chrono::duration_cast
+ (
+ local_clock_type::now().time_since_epoch()
+ ).count()
+ );
+
+ return static_cast(current_now);
+ }
+
+ template
+ auto is_close_fraction(const NumericType& a,
+ const NumericType& b,
+ const NumericType& tol) noexcept -> bool
+ {
+ using std::fabs;
+
+ auto result_is_ok = bool { };
+
+ NumericType delta { };
+
+ if(b == static_cast(0))
+ {
+ delta = fabs(a - b); // LCOV_EXCL_LINE
+
+ result_is_ok = (delta < tol); // LCOV_EXCL_LINE
+ }
+ else
+ {
+ delta = fabs(1 - (a / b));
+
+ result_is_ok = (delta < tol);
+ }
+
+ return result_is_ok;
+ }
+
+ template
+ bool test_edges()
+ {
+ using float_type = FloatType;
+ using ctrl_type = boost::multiprecision::number, boost::multiprecision::et_off>;
+
+ std::mt19937_64 gen { time_point() };
+
+ auto dis =
+ std::uniform_real_distribution
+ {
+ static_cast(1.01F),
+ static_cast(1.04F)
+ };
+
+ bool result_is_ok { true };
+
+ {
+ float_type flt_val { (std::numeric_limits::max)() };
+ ctrl_type ctl_val { flt_val };
+
+ for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT8_C(16)); ++i)
+ {
+ static_cast(i);
+
+ float_type flt_denom { 2345.6F * dis(gen) };
+
+ flt_val /= flt_denom;
+ ctl_val /= ctrl_type { flt_denom };
+
+ const bool result_div_is_ok { local::is_close_fraction(flt_val, float_type { ctl_val }, std::numeric_limits::epsilon() * 32) };
+
+ BOOST_TEST(result_div_is_ok);
+
+ result_is_ok = (result_div_is_ok && result_is_ok);
+ }
+ }
+
+ {
+ float_type flt_val { (std::numeric_limits::min)() };
+ ctrl_type ctl_val { flt_val };
+
+ for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT8_C(16)); ++i)
+ {
+ static_cast(i);
+
+ float_type flt_factor { 2345.6F * dis(gen) };
+
+ flt_val *= flt_factor;
+ ctl_val *= ctrl_type { flt_factor };
+
+ const bool result_mul_is_ok { local::is_close_fraction(flt_val, float_type { ctl_val }, std::numeric_limits::epsilon() * 32) };
+
+ BOOST_TEST(result_mul_is_ok);
+
+ result_is_ok = (result_mul_is_ok && result_is_ok);
+ }
+ }
+
+ {
+ float_type flt_val { (std::numeric_limits::max)() };
+ ctrl_type ctl_val { flt_val };
+
+ for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT8_C(16)); ++i)
+ {
+ static_cast(i);
+
+ float_type flt_factor { 1234.56e-12F * dis(gen) };
+
+ flt_val *= flt_factor;
+ ctl_val *= ctrl_type { flt_factor };
+
+ const bool result_mul_is_ok { local::is_close_fraction(flt_val, float_type { ctl_val }, std::numeric_limits::epsilon() * 32) };
+
+ BOOST_TEST(result_mul_is_ok);
+
+ result_is_ok = (result_mul_is_ok && result_is_ok);
+ }
+ }
+
+ {
+ float_type flt_val { (std::numeric_limits::max)() };
+ ctrl_type ctl_val { flt_val };
+
+ for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT8_C(16)); ++i)
+ {
+ static_cast(i);
+
+ float_type flt_factor { 1234.56e-12F * dis(gen) };
+
+ flt_val = flt_factor * flt_val;
+ ctl_val *= ctrl_type { flt_factor };
+
+ const bool result_mul_is_ok { local::is_close_fraction(flt_val, float_type { ctl_val }, std::numeric_limits::epsilon() * 32) };
+
+ BOOST_TEST(result_mul_is_ok);
+
+ result_is_ok = (result_mul_is_ok && result_is_ok);
+ }
+ }
+
+ {
+ float_type flt_val { };
+ ctrl_type ctl_val { };
+
+ for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT8_C(16)); ++i)
+ {
+ static_cast(i);
+
+ flt_val = sqrt((std::numeric_limits::max)());
+ ctl_val = ctrl_type { flt_val };
+
+ float_type flt_factor { 123.456F * dis(gen) };
+
+ unsigned j { static_cast(UINT8_C(0)) };
+
+ for(; j < static_cast(UINT16_C(8192)); ++j)
+ {
+ if(unsigned { j % unsigned { UINT8_C(3) } } == unsigned { UINT8_C(0)})
+ {
+ flt_val = -flt_val;
+ ctl_val = -ctl_val;
+ }
+
+ if(unsigned { j % unsigned { UINT8_C(2) } } == unsigned { UINT8_C(0)})
+ {
+ flt_factor = -flt_factor;
+ }
+
+ flt_val *= flt_factor;
+ ctl_val *= ctrl_type { flt_factor };
+
+ if(isinf(flt_val)) { break; }
+
+ const bool result_finite_mul_is_ok
+ {
+ local::is_close_fraction(flt_val, float_type { ctl_val }, std::numeric_limits::epsilon() * 32)
+ && (signbit(flt_val) == signbit(ctl_val))
+ };
+
+ BOOST_TEST(result_finite_mul_is_ok);
+ }
+
+ const bool result_mul_is_ok
+ {
+ isinf(flt_val)
+ && (j < unsigned { UINT16_C(8192) })
+ && (signbit(flt_val) == signbit(ctl_val))
+ };
+
+ BOOST_TEST(result_mul_is_ok);
+
+ result_is_ok = (result_mul_is_ok && result_is_ok);
+ }
+ }
+
+ {
+ const float_type inf_pos_01 { "1e100001" };
+ const float_type inf_pos_02 { "1e100002" };
+ const float_type inf_pos_03 { "1e100003" };
+ const float_type inf_neg_01 { "-1e100001" };
+ const float_type inf_neg_02 { "-1e100002" };
+ const float_type inf_neg_03 { "-1e100003" };
+
+ const float_type tiny_01 { "1e-100001" };
+ const float_type tiny_02 { "1e-100002" };
+ const float_type tiny_03 { "1e-100003" };
+
+ BOOST_TEST(result_is_ok = (isinf(inf_pos_01) && result_is_ok));
+ BOOST_TEST(result_is_ok = (isinf(inf_pos_02) && result_is_ok));
+ BOOST_TEST(result_is_ok = (isinf(inf_pos_03) && result_is_ok));
+
+ BOOST_TEST(result_is_ok = (isinf(inf_neg_01) && signbit(inf_neg_01) && result_is_ok));
+ BOOST_TEST(result_is_ok = (isinf(inf_neg_02) && signbit(inf_neg_02) && result_is_ok));
+ BOOST_TEST(result_is_ok = (isinf(inf_neg_03) && signbit(inf_neg_03) && result_is_ok));
+
+ BOOST_TEST(result_is_ok = ((fpclassify(tiny_01) == FP_ZERO) && result_is_ok));
+ BOOST_TEST(result_is_ok = ((fpclassify(tiny_02) == FP_ZERO) && result_is_ok));
+ BOOST_TEST(result_is_ok = ((fpclassify(tiny_03) == FP_ZERO) && result_is_ok));
+ }
+
+ for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT8_C(8)); ++i)
+ {
+ static_cast(i);
+
+ float_type flt_x { 2345.6F + static_cast(i) * dis(gen) };
+
+ const float_type quotient_one = flt_x /= flt_x;
+
+ BOOST_TEST(result_is_ok = ((quotient_one == 1) && result_is_ok));
+ }
+
+ for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT8_C(8)); ++i)
+ {
+ static_cast(i);
+
+ float_type flt_x { 1000.0F + static_cast(i) * dis(gen) };
+
+ const float_type sub_result_zero = flt_x -= flt_x;
+
+ BOOST_TEST(result_is_ok = ((fpclassify(sub_result_zero) == FP_ZERO) && result_is_ok));
+ }
+
+ for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT8_C(8)); ++i)
+ {
+ static_cast(i);
+
+ float_type flt_numpos { ::my_one() * dis(gen) };
+ float_type flt_numneg { ::my_one() * -dis(gen) };
+ float_type flt_denom { ::my_zero() * dis(gen) };
+
+ const float_type div_result_zero_pos { flt_numpos / flt_denom };
+ const float_type div_result_zero_neg { flt_numneg / flt_denom };
+
+ BOOST_TEST(result_is_ok = ((fpclassify(div_result_zero_pos) == FP_INFINITE) && result_is_ok));
+ BOOST_TEST(result_is_ok = ((fpclassify(div_result_zero_neg) == FP_INFINITE) && signbit(div_result_zero_neg) && result_is_ok));
+ }
+
+ for(auto i = static_cast(UINT8_C(0)); i < static_cast