mirror of
https://github.com/boostorg/multiprecision.git
synced 2026-07-21 13:23:49 +00:00
Fix up cpp_bin_float for very small bit counts. (#577)
Fix up cpp_bin_float for very small bit counts. Adds support for emulating float16_t and bfloat16_t. Also adds test cases, and updates test_arithmetic.hpp to cope with testing small bit count types. Fixes https://github.com/boostorg/multiprecision/issues/576.
This commit is contained in:
@@ -300,7 +300,13 @@ class cpp_bin_float
|
||||
|
||||
#ifdef BOOST_HAS_FLOAT128
|
||||
template <class Float>
|
||||
typename std::enable_if<std::is_same<Float, float128_type>::value, cpp_bin_float&>::type assign_float(Float f)
|
||||
typename std::enable_if<std::is_same<Float, float128_type>::value && (std::numeric_limits<Float>::digits > Digits), cpp_bin_float&>::type assign_float(Float f)
|
||||
{
|
||||
cpp_bin_float<113, DigitBase, Allocator, Exponent, MinExponent, MaxExponent> bf(f);
|
||||
return *this = bf;
|
||||
}
|
||||
template <class Float>
|
||||
typename std::enable_if<std::is_same<Float, float128_type>::value && (std::numeric_limits<Float>::digits <= Digits), cpp_bin_float&>::type assign_float(Float f)
|
||||
{
|
||||
using default_ops::eval_add;
|
||||
using bf_int_type = typename boost::multiprecision::detail::canonical<int, cpp_bin_float>::type;
|
||||
@@ -337,7 +343,7 @@ class cpp_bin_float
|
||||
m_sign = false;
|
||||
m_exponent = 0;
|
||||
|
||||
constexpr std::ptrdiff_t bits = sizeof(int) * CHAR_BIT - 1;
|
||||
constexpr std::ptrdiff_t bits = sizeof(int) * CHAR_BIT - 1 < MaxExponent - 1 ? sizeof(int) * CHAR_BIT - 1 : 3;
|
||||
int e;
|
||||
f = frexpq(f, &e);
|
||||
while (f)
|
||||
@@ -352,15 +358,36 @@ class cpp_bin_float
|
||||
eval_add(*this, t);
|
||||
}
|
||||
m_exponent += static_cast<Exponent>(e);
|
||||
if (m_exponent > max_exponent)
|
||||
{
|
||||
m_exponent = exponent_infinity;
|
||||
m_data = static_cast<ui_type>(0u);
|
||||
}
|
||||
else if (m_exponent < min_exponent)
|
||||
{
|
||||
m_exponent = exponent_zero;
|
||||
m_data = static_cast<ui_type>(0u);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
#ifdef BOOST_HAS_FLOAT128
|
||||
template <class Float>
|
||||
typename std::enable_if<std::is_floating_point<Float>::value && !std::is_same<Float, float128_type>::value, cpp_bin_float&>::type assign_float(Float f)
|
||||
typename std::enable_if<std::is_floating_point<Float>::value && !std::is_same<Float, float128_type>::value && (std::numeric_limits<Float>::digits > Digits), cpp_bin_float&>::type assign_float(Float f)
|
||||
#else
|
||||
template <class Float>
|
||||
typename std::enable_if<std::is_floating_point<Float>::value, cpp_bin_float&>::type assign_float(Float f)
|
||||
typename std::enable_if<std::is_floating_point<Float>::value && (std::numeric_limits<Float>::digits > Digits), cpp_bin_float&>::type assign_float(Float f)
|
||||
#endif
|
||||
{
|
||||
cpp_bin_float<std::numeric_limits<Float>::digits, DigitBase, Allocator, Exponent, MinExponent, MaxExponent> bf(f);
|
||||
return *this = bf;
|
||||
}
|
||||
#ifdef BOOST_HAS_FLOAT128
|
||||
template <class Float>
|
||||
typename std::enable_if<std::is_floating_point<Float>::value && !std::is_same<Float, float128_type>::value && (std::numeric_limits<Float>::digits <= Digits), cpp_bin_float&>::type assign_float(Float f)
|
||||
#else
|
||||
template <class Float>
|
||||
typename std::enable_if<std::is_floating_point<Float>::value && (std::numeric_limits<Float>::digits <= Digits), cpp_bin_float&>::type assign_float(Float f)
|
||||
#endif
|
||||
{
|
||||
using std::frexp;
|
||||
@@ -399,7 +426,13 @@ class cpp_bin_float
|
||||
m_sign = false;
|
||||
m_exponent = 0;
|
||||
|
||||
constexpr std::ptrdiff_t bits = sizeof(int) * CHAR_BIT - 1;
|
||||
//
|
||||
// This code picks off the bits in f a few at a time and injects them into *this.
|
||||
// It does not do roundingm so we must have more digits precision in *this than
|
||||
// in the floating point value (the normal situation, unless we're emulating another
|
||||
// type like float16_t).
|
||||
//
|
||||
constexpr std::ptrdiff_t bits = static_cast<std::ptrdiff_t>(sizeof(int) * CHAR_BIT - 1) < static_cast<std::ptrdiff_t>(MaxExponent - 1) ? static_cast<std::ptrdiff_t>(sizeof(int) * CHAR_BIT - 1) : 3;
|
||||
int e;
|
||||
f = frexp(f, &e);
|
||||
while (f != static_cast<Float>(0.0F))
|
||||
@@ -414,6 +447,16 @@ class cpp_bin_float
|
||||
eval_add(*this, t);
|
||||
}
|
||||
m_exponent += static_cast<Exponent>(e);
|
||||
if (m_exponent > max_exponent)
|
||||
{
|
||||
m_exponent = exponent_infinity;
|
||||
m_data = static_cast<ui_type>(0u);
|
||||
}
|
||||
else if(m_exponent < min_exponent)
|
||||
{
|
||||
m_exponent = exponent_zero;
|
||||
m_data = static_cast<ui_type>(0u);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -514,7 +557,12 @@ class cpp_bin_float
|
||||
using ar_type = typename boost::multiprecision::detail::canonical<ui_type, rep_type>::type;
|
||||
m_data = static_cast<ar_type>(fi);
|
||||
std::size_t shift = msb(fi);
|
||||
if (shift >= bit_count)
|
||||
if (shift > max_exponent)
|
||||
{
|
||||
m_exponent = exponent_infinity;
|
||||
m_data = static_cast<limb_type>(0);
|
||||
}
|
||||
else if (shift >= bit_count)
|
||||
{
|
||||
m_exponent = static_cast<Exponent>(shift);
|
||||
m_data = static_cast<ar_type>(fi >> (shift + 1 - bit_count));
|
||||
@@ -524,7 +572,7 @@ class cpp_bin_float
|
||||
m_exponent = static_cast<Exponent>(shift);
|
||||
eval_left_shift(m_data, bit_count - shift - 1);
|
||||
}
|
||||
BOOST_MP_ASSERT(eval_bit_test(m_data, bit_count - 1));
|
||||
BOOST_MP_ASSERT((m_exponent == exponent_infinity) || eval_bit_test(m_data, bit_count - 1));
|
||||
m_sign = detail::is_negative(i);
|
||||
}
|
||||
return *this;
|
||||
@@ -1281,7 +1329,7 @@ inline void eval_divide(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, Mi
|
||||
|
||||
template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE,
|
||||
class Allocator2, class Exponent2, Exponent MinE2, Exponent MaxE2, class U>
|
||||
inline typename std::enable_if<boost::multiprecision::detail::is_unsigned<U>::value>::type eval_divide(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res,
|
||||
inline typename std::enable_if<boost::multiprecision::detail::is_unsigned<U>::value && (std::numeric_limits<U>::digits <= Digits)>::type eval_divide(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res,
|
||||
const cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2>& u, const U& v)
|
||||
{
|
||||
#ifdef BOOST_MSVC
|
||||
@@ -1396,14 +1444,14 @@ inline typename std::enable_if<boost::multiprecision::detail::is_unsigned<U>::va
|
||||
}
|
||||
|
||||
template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, class U>
|
||||
inline typename std::enable_if<boost::multiprecision::detail::is_unsigned<U>::value>::type eval_divide(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res, const U& v)
|
||||
inline typename std::enable_if<boost::multiprecision::detail::is_unsigned<U>::value && (std::numeric_limits<U>::digits <= Digits)>::type eval_divide(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res, const U& v)
|
||||
{
|
||||
eval_divide(res, res, v);
|
||||
}
|
||||
|
||||
template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE,
|
||||
class Allocator2, class Exponent2, Exponent MinE2, Exponent MaxE2, class S>
|
||||
inline typename std::enable_if<boost::multiprecision::detail::is_signed<S>::value && boost::multiprecision::detail::is_integral<S>::value>::type eval_divide(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res,
|
||||
inline typename std::enable_if<boost::multiprecision::detail::is_signed<S>::value && boost::multiprecision::detail::is_integral<S>::value && (std::numeric_limits<S>::digits <= Digits)>::type eval_divide(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res,
|
||||
const cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2>& u, const S& v)
|
||||
{
|
||||
using ui_type = typename boost::multiprecision::detail::make_unsigned<S>::type;
|
||||
@@ -1413,7 +1461,7 @@ inline typename std::enable_if<boost::multiprecision::detail::is_signed<S>::valu
|
||||
}
|
||||
|
||||
template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, class S>
|
||||
inline typename std::enable_if<boost::multiprecision::detail::is_signed<S>::value && boost::multiprecision::detail::is_integral<S>::value>::type eval_divide(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res, const S& v)
|
||||
inline typename std::enable_if<boost::multiprecision::detail::is_signed<S>::value && boost::multiprecision::detail::is_integral<S>::value && (std::numeric_limits<S>::digits <= Digits)>::type eval_divide(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res, const S& v)
|
||||
{
|
||||
eval_divide(res, res, v);
|
||||
}
|
||||
@@ -1658,7 +1706,7 @@ inline typename std::enable_if<std::is_floating_point<Float>::value>::type eval_
|
||||
//
|
||||
// Perform rounding first, then afterwards extract the digits:
|
||||
//
|
||||
cpp_bin_float<static_cast<unsigned>(float_digits), digit_base_2, Allocator, Exponent, MinE, MaxE> arg;
|
||||
cpp_bin_float<static_cast<unsigned>(float_digits), digit_base_2, Allocator, Exponent, 0, 0> arg;
|
||||
typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::rep_type bits(original_arg.bits());
|
||||
arg.exponent() = original_arg.exponent();
|
||||
copy_and_round(arg, bits, (std::ptrdiff_t)digits_to_round_to);
|
||||
|
||||
@@ -127,6 +127,7 @@ test-suite arithmetic_tests :
|
||||
[ run test_arithmetic_cpp_bin_float_3.cpp no_eh_support : : : <toolset>msvc:<cxxflags>-bigobj [ check-target-builds ../config//has_float128 : <source>quadmath ] ]
|
||||
[ run test_arithmetic_cpp_bin_float_4.cpp no_eh_support : : : <toolset>msvc:<cxxflags>-bigobj [ check-target-builds ../config//has_float128 : <source>quadmath ] ]
|
||||
[ run test_arithmetic_cpp_bin_float_5.cpp no_eh_support : : : <toolset>msvc:<cxxflags>-bigobj [ check-target-builds ../config//has_float128 : <source>quadmath ] ]
|
||||
[ run test_arithmetic_cpp_bin_float_6.cpp no_eh_support : : : <toolset>msvc:<cxxflags>-bigobj [ check-target-builds ../config//has_float128 : <source>quadmath ] [ requires cxx17_if_constexpr ] ]
|
||||
|
||||
[ run test_arithmetic_mpf_50.cpp gmp no_eh_support : : : [ check-target-builds ../config//has_gmp : : <build>no ] [ check-target-builds ../config//has_float128 : <source>quadmath ] ]
|
||||
[ run test_arithmetic_mpf.cpp gmp no_eh_support : : : [ check-target-builds ../config//has_gmp : : <build>no ] [ check-target-builds ../config//has_float128 : <source>quadmath ] ]
|
||||
@@ -1232,6 +1233,7 @@ test-suite misc :
|
||||
[ run git_issue_526.cpp ]
|
||||
[ run git_issue_540.cpp ]
|
||||
[ run git_issue_573.cpp : : : <toolset>msvc:<cxxflags>-sdl ]
|
||||
[ run git_issue_576.cpp : : : [ check-target-builds ../config//has_float128 : <define>TEST_FLOAT128 <source>quadmath : ] ]
|
||||
[ compile git_issue_98.cpp :
|
||||
[ check-target-builds ../config//has_float128 : <define>TEST_FLOAT128 <source>quadmath : ]
|
||||
[ check-target-builds ../config//has_gmp : <define>TEST_GMP <source>gmp : ]
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2023 John Maddock. 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)
|
||||
|
||||
#include <boost/multiprecision/cpp_bin_float.hpp>
|
||||
#include <iostream>
|
||||
#include "test.hpp"
|
||||
|
||||
template <class Float, class F>
|
||||
void test(F f, bool big)
|
||||
{
|
||||
Float f2(f);
|
||||
if (big)
|
||||
{
|
||||
F tol = f * static_cast<F>(std::numeric_limits<Float>::epsilon());
|
||||
F max = static_cast<F>((std::numeric_limits<Float>::max)());
|
||||
F diff = static_cast<F>(f2) - f;
|
||||
if (diff < 0)
|
||||
diff = -diff;
|
||||
if (f > max)
|
||||
{
|
||||
BOOST_CHECK(isinf(f2) || (diff < tol));
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_CHECK_LE(diff, tol);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_CHECK_EQUAL(static_cast<F>(f2), f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class Float>
|
||||
void test()
|
||||
{
|
||||
std::int64_t i = static_cast<std::int64_t>(1) << (std::numeric_limits<Float>::max_exponent + 1);
|
||||
Float f(i);
|
||||
BOOST_CHECK_EQUAL(f, std::numeric_limits<Float>::infinity());
|
||||
|
||||
if (std::numeric_limits<Float>::max_exponent < std::numeric_limits<float>::digits)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(Float(static_cast<float>(i)), std::numeric_limits<Float>::infinity());
|
||||
}
|
||||
if (std::numeric_limits<Float>::max_exponent < std::numeric_limits<double>::digits)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(Float(static_cast<double>(i)), std::numeric_limits<Float>::infinity());
|
||||
}
|
||||
if (std::numeric_limits<Float>::max_exponent < std::numeric_limits<long double>::digits)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(Float(static_cast<long double>(i)), std::numeric_limits<Float>::infinity());
|
||||
}
|
||||
#ifdef BOOST_HAS_FLOAT128
|
||||
if (std::numeric_limits<Float>::max_exponent < std::numeric_limits<__float128>::digits)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(Float(static_cast<__float128>(i)), std::numeric_limits<Float>::infinity());
|
||||
}
|
||||
#endif
|
||||
|
||||
--i;
|
||||
|
||||
while (i)
|
||||
{
|
||||
Float f2(i);
|
||||
BOOST_CHECK_NE(f2, std::numeric_limits<Float>::infinity());
|
||||
bool big = boost::multiprecision::msb(i) >= std::numeric_limits<Float>::digits;
|
||||
if (big)
|
||||
{
|
||||
BOOST_CHECK_LE(static_cast<std::int64_t>(f2), i);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_CHECK_EQUAL(static_cast<std::int64_t>(f2), i);
|
||||
}
|
||||
|
||||
if (std::numeric_limits<Float>::max_exponent < std::numeric_limits<float>::digits)
|
||||
{
|
||||
test<Float>(static_cast<float>(i), big);
|
||||
for (int exp = -1; exp >= std::numeric_limits<Float>::min_exponent; --exp)
|
||||
test<Float>(std::ldexp(static_cast<float>(i), exp), big);
|
||||
}
|
||||
if (std::numeric_limits<Float>::max_exponent < std::numeric_limits<double>::digits)
|
||||
{
|
||||
test<Float>(static_cast<double>(i), big);
|
||||
for (int exp = -1; exp >= std::numeric_limits<Float>::min_exponent; --exp)
|
||||
test<Float>(std::ldexp(static_cast<double>(i), exp), big);
|
||||
}
|
||||
if (std::numeric_limits<Float>::max_exponent < std::numeric_limits<long double>::digits)
|
||||
{
|
||||
test<Float>(static_cast<long double>(i), big);
|
||||
for (int exp = -1; exp >= std::numeric_limits<Float>::min_exponent; --exp)
|
||||
test<Float>(std::ldexp(static_cast<long double>(i), exp), big);
|
||||
}
|
||||
#ifdef BOOST_HAS_FLOAT128
|
||||
if (std::numeric_limits<Float>::max_exponent < std::numeric_limits<__float128>::digits)
|
||||
{
|
||||
test<Float>(static_cast<__float128>(i), big);
|
||||
for (int exp = -1; exp >= std::numeric_limits<Float>::min_exponent; --exp)
|
||||
test<Float>(ldexpq(static_cast<__float128>(i), exp), big);
|
||||
}
|
||||
#endif
|
||||
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace boost::multiprecision;
|
||||
typedef number<backends::cpp_bin_float<11, backends::digit_base_2, void, std::int16_t, -14, 15>, et_off> float16_t;
|
||||
//typedef number<backends::cpp_bin_float<8, backends::digit_base_2, void, std::int16_t, -126, 127>, et_off> bfloat16_t;
|
||||
|
||||
test<float16_t>();
|
||||
//test<bfloat16_t>();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
+150
-116
@@ -16,6 +16,7 @@
|
||||
#include <iomanip>
|
||||
#include "test.hpp"
|
||||
#include <boost/multiprecision/detail/standalone_config.hpp>
|
||||
#include <boost/multiprecision/integer.hpp>
|
||||
|
||||
#ifndef BOOST_MP_STANDALONE
|
||||
#include <boost/integer/common_factor_rt.hpp>
|
||||
@@ -1186,16 +1187,16 @@ void test_float_funcs(const std::integral_constant<bool, true>&)
|
||||
a = -2;
|
||||
a = fabs(a);
|
||||
BOOST_CHECK_EQUAL(a, 2);
|
||||
a = 2.5;
|
||||
a = static_cast<Real>(2.5);
|
||||
a = floor(a);
|
||||
BOOST_CHECK_EQUAL(a, 2);
|
||||
a = 2.5;
|
||||
a = static_cast<Real>(2.5);
|
||||
a = ceil(a);
|
||||
BOOST_CHECK_EQUAL(a, 3);
|
||||
a = 2.5;
|
||||
a = static_cast<Real>(2.5);
|
||||
a = trunc(a);
|
||||
BOOST_CHECK_EQUAL(a, 2);
|
||||
a = 2.25;
|
||||
a = static_cast<Real>(2.25);
|
||||
a = round(a);
|
||||
BOOST_CHECK_EQUAL(a, 2);
|
||||
a = 2;
|
||||
@@ -1203,7 +1204,10 @@ void test_float_funcs(const std::integral_constant<bool, true>&)
|
||||
BOOST_CHECK_EQUAL(a, 4);
|
||||
int i;
|
||||
a = frexp(a, &i);
|
||||
BOOST_CHECK_EQUAL(a, 0.5);
|
||||
BOOST_IF_CONSTEXPR(std::is_convertible<double, Real>::value)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(a, 0.5);
|
||||
}
|
||||
|
||||
Real tol = std::numeric_limits<Real>::epsilon() * 3;
|
||||
a = 4;
|
||||
@@ -1219,31 +1223,31 @@ void test_float_funcs(const std::integral_constant<bool, true>&)
|
||||
a = log10(a);
|
||||
BOOST_CHECK_CLOSE_FRACTION(a, Real(log10(Real(3))), tol);
|
||||
|
||||
a = 0.5;
|
||||
a = static_cast<Real>(0.5);
|
||||
a = sin(a);
|
||||
BOOST_CHECK_CLOSE_FRACTION(a, Real(sin(Real(0.5))), tol);
|
||||
a = 0.5;
|
||||
a = static_cast<Real>(0.5);
|
||||
a = cos(a);
|
||||
BOOST_CHECK_CLOSE_FRACTION(a, Real(cos(Real(0.5))), tol);
|
||||
a = 0.5;
|
||||
a = static_cast<Real>(0.5);
|
||||
a = tan(a);
|
||||
BOOST_CHECK_CLOSE_FRACTION(a, Real(tan(Real(0.5))), tol);
|
||||
a = 0.5;
|
||||
a = static_cast<Real>(0.5);
|
||||
a = asin(a);
|
||||
BOOST_CHECK_CLOSE_FRACTION(a, Real(asin(Real(0.5))), tol);
|
||||
a = 0.5;
|
||||
a = static_cast<Real>(0.5);
|
||||
a = acos(a);
|
||||
BOOST_CHECK_CLOSE_FRACTION(a, Real(acos(Real(0.5))), tol);
|
||||
a = 0.5;
|
||||
a = static_cast<Real>(0.5);
|
||||
a = atan(a);
|
||||
BOOST_CHECK_CLOSE_FRACTION(a, Real(atan(Real(0.5))), tol);
|
||||
a = 0.5;
|
||||
a = static_cast<Real>(0.5);
|
||||
a = sinh(a);
|
||||
BOOST_CHECK_CLOSE_FRACTION(a, Real(sinh(Real(0.5))), tol);
|
||||
a = 0.5;
|
||||
a = static_cast<Real>(0.5);
|
||||
a = cosh(a);
|
||||
BOOST_CHECK_CLOSE_FRACTION(a, Real(cosh(Real(0.5))), tol);
|
||||
a = 0.5;
|
||||
a = static_cast<Real>(0.5);
|
||||
a = tanh(a);
|
||||
BOOST_CHECK_CLOSE_FRACTION(a, Real(tanh(Real(0.5))), tol);
|
||||
// fmod, need to check all the sign permutations:
|
||||
@@ -1378,39 +1382,42 @@ void test_float_funcs(const std::integral_constant<bool, true>&)
|
||||
template <class T, class U>
|
||||
void compare_NaNs(const T& a, const U& b)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(a == b, false);
|
||||
BOOST_CHECK_EQUAL(a != b, true);
|
||||
BOOST_CHECK_EQUAL(a <= b, false);
|
||||
BOOST_CHECK_EQUAL(a >= b, false);
|
||||
BOOST_CHECK_EQUAL(a > b, false);
|
||||
BOOST_CHECK_EQUAL(a < b, false);
|
||||
//
|
||||
// Again where LHS may be an expression template:
|
||||
//
|
||||
BOOST_CHECK_EQUAL(1 * a == b, false);
|
||||
BOOST_CHECK_EQUAL(1 * a != b, true);
|
||||
BOOST_CHECK_EQUAL(1 * a <= b, false);
|
||||
BOOST_CHECK_EQUAL(1 * a >= b, false);
|
||||
BOOST_CHECK_EQUAL(1 * a > b, false);
|
||||
BOOST_CHECK_EQUAL(1 * a < b, false);
|
||||
//
|
||||
// Again where RHS may be an expression template:
|
||||
//
|
||||
BOOST_CHECK_EQUAL(a == b * 1, false);
|
||||
BOOST_CHECK_EQUAL(a != b * 1, true);
|
||||
BOOST_CHECK_EQUAL(a <= b * 1, false);
|
||||
BOOST_CHECK_EQUAL(a >= b * 1, false);
|
||||
BOOST_CHECK_EQUAL(a > b * 1, false);
|
||||
BOOST_CHECK_EQUAL(a < b * 1, false);
|
||||
//
|
||||
// Again where LHS and RHS may be an expression templates:
|
||||
//
|
||||
BOOST_CHECK_EQUAL(1 * a == b * 1, false);
|
||||
BOOST_CHECK_EQUAL(1 * a != b * 1, true);
|
||||
BOOST_CHECK_EQUAL(1 * a <= b * 1, false);
|
||||
BOOST_CHECK_EQUAL(1 * a >= b * 1, false);
|
||||
BOOST_CHECK_EQUAL(1 * a > b * 1, false);
|
||||
BOOST_CHECK_EQUAL(1 * a < b * 1, false);
|
||||
BOOST_IF_CONSTEXPR(std::is_convertible<U, T>::value)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(a == b, false);
|
||||
BOOST_CHECK_EQUAL(a != b, true);
|
||||
BOOST_CHECK_EQUAL(a <= b, false);
|
||||
BOOST_CHECK_EQUAL(a >= b, false);
|
||||
BOOST_CHECK_EQUAL(a > b, false);
|
||||
BOOST_CHECK_EQUAL(a < b, false);
|
||||
//
|
||||
// Again where LHS may be an expression template:
|
||||
//
|
||||
BOOST_CHECK_EQUAL(1 * a == b, false);
|
||||
BOOST_CHECK_EQUAL(1 * a != b, true);
|
||||
BOOST_CHECK_EQUAL(1 * a <= b, false);
|
||||
BOOST_CHECK_EQUAL(1 * a >= b, false);
|
||||
BOOST_CHECK_EQUAL(1 * a > b, false);
|
||||
BOOST_CHECK_EQUAL(1 * a < b, false);
|
||||
//
|
||||
// Again where RHS may be an expression template:
|
||||
//
|
||||
BOOST_CHECK_EQUAL(a == b * 1, false);
|
||||
BOOST_CHECK_EQUAL(a != b * 1, true);
|
||||
BOOST_CHECK_EQUAL(a <= b * 1, false);
|
||||
BOOST_CHECK_EQUAL(a >= b * 1, false);
|
||||
BOOST_CHECK_EQUAL(a > b * 1, false);
|
||||
BOOST_CHECK_EQUAL(a < b * 1, false);
|
||||
//
|
||||
// Again where LHS and RHS may be an expression templates:
|
||||
//
|
||||
BOOST_CHECK_EQUAL(1 * a == b * 1, false);
|
||||
BOOST_CHECK_EQUAL(1 * a != b * 1, true);
|
||||
BOOST_CHECK_EQUAL(1 * a <= b * 1, false);
|
||||
BOOST_CHECK_EQUAL(1 * a >= b * 1, false);
|
||||
BOOST_CHECK_EQUAL(1 * a > b * 1, false);
|
||||
BOOST_CHECK_EQUAL(1 * a < b * 1, false);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Real, class T>
|
||||
@@ -1438,24 +1445,36 @@ void test_float_ops(const std::integral_constant<int, boost::multiprecision::num
|
||||
Real v(512);
|
||||
e_type exponent;
|
||||
Real r = frexp(v, &exponent);
|
||||
BOOST_CHECK_EQUAL(r, 0.5);
|
||||
BOOST_IF_CONSTEXPR(std::is_convertible<double, Real>::value)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(r, 0.5);
|
||||
}
|
||||
BOOST_CHECK_EQUAL(exponent, 10);
|
||||
BOOST_CHECK_EQUAL(v, 512);
|
||||
v = 1 / v;
|
||||
r = frexp(v, &exponent);
|
||||
BOOST_CHECK_EQUAL(r, 0.5);
|
||||
BOOST_IF_CONSTEXPR(std::is_convertible<double, Real>::value)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(r, 0.5);
|
||||
}
|
||||
BOOST_CHECK_EQUAL(exponent, -8);
|
||||
BOOST_CHECK_EQUAL(ldexp(Real(2), e_type(5)), 64);
|
||||
BOOST_CHECK_EQUAL(ldexp(Real(2), e_type(-5)), Real(2) / 32);
|
||||
v = 512;
|
||||
e_type exp2;
|
||||
r = frexp(v, &exp2);
|
||||
BOOST_CHECK_EQUAL(r, 0.5);
|
||||
BOOST_IF_CONSTEXPR(std::is_convertible<double, Real>::value)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(r, 0.5);
|
||||
}
|
||||
BOOST_CHECK_EQUAL(exp2, 10);
|
||||
BOOST_CHECK_EQUAL(v, 512);
|
||||
v = 1 / v;
|
||||
r = frexp(v, &exp2);
|
||||
BOOST_CHECK_EQUAL(r, 0.5);
|
||||
BOOST_IF_CONSTEXPR(std::is_convertible<double, Real>::value)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(r, 0.5);
|
||||
}
|
||||
BOOST_CHECK_EQUAL(exp2, -8);
|
||||
//
|
||||
// scalbn and logb, these are the same as ldexp and frexp unless the radix is
|
||||
@@ -1463,8 +1482,11 @@ void test_float_ops(const std::integral_constant<int, boost::multiprecision::num
|
||||
//
|
||||
BOOST_IF_CONSTEXPR (std::numeric_limits<Real>::is_specialized && std::numeric_limits<Real>::radix)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(scalbn(Real(2), 5), 2 * pow(double(std::numeric_limits<Real>::radix), 5));
|
||||
BOOST_CHECK_EQUAL(scalbn(Real(2), -5), Real(2) / pow(double(std::numeric_limits<Real>::radix), 5));
|
||||
BOOST_IF_CONSTEXPR(std::is_convertible<double, Real>::value)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(scalbn(Real(2), 5), 2 * pow(double(std::numeric_limits<Real>::radix), 5));
|
||||
BOOST_CHECK_EQUAL(scalbn(Real(2), -5), Real(2) / pow(double(std::numeric_limits<Real>::radix), 5));
|
||||
}
|
||||
v = 512;
|
||||
exponent = ilogb(v);
|
||||
r = scalbn(v, -exponent);
|
||||
@@ -1484,68 +1506,71 @@ void test_float_ops(const std::integral_constant<int, boost::multiprecision::num
|
||||
// pow and exponent:
|
||||
//
|
||||
#ifndef BOOST_MP_STANDALONE
|
||||
v = 3.25;
|
||||
r = pow(v, 0);
|
||||
BOOST_CHECK_EQUAL(r, 1);
|
||||
r = pow(v, 1);
|
||||
BOOST_CHECK_EQUAL(r, 3.25);
|
||||
r = pow(v, 2);
|
||||
BOOST_CHECK_EQUAL(r, boost::math::pow<2>(3.25));
|
||||
r = pow(v, 3);
|
||||
BOOST_CHECK_EQUAL(r, boost::math::pow<3>(3.25));
|
||||
|
||||
BOOST_IF_CONSTEXPR(std::numeric_limits<Real>::digits10 > 11)
|
||||
BOOST_IF_CONSTEXPR(std::is_convertible<double, Real>::value)
|
||||
{
|
||||
// (13/4)^4
|
||||
// 28561 / 256
|
||||
// 111.56640625
|
||||
r = pow(v, 4);
|
||||
BOOST_CHECK_EQUAL(r, boost::math::pow<4>(Real(3.25)));
|
||||
}
|
||||
v = 3.25;
|
||||
r = pow(v, 0);
|
||||
BOOST_CHECK_EQUAL(r, 1);
|
||||
r = pow(v, 1);
|
||||
BOOST_CHECK_EQUAL(r, 3.25);
|
||||
r = pow(v, 2);
|
||||
BOOST_CHECK_EQUAL(r, boost::math::pow<2>(3.25));
|
||||
r = pow(v, 3);
|
||||
BOOST_CHECK_EQUAL(r, boost::math::pow<3>(3.25));
|
||||
|
||||
BOOST_IF_CONSTEXPR(std::numeric_limits<Real>::digits10 > 13)
|
||||
{
|
||||
// (13/4)^5
|
||||
// 371293 / 1024
|
||||
// 362.5908203125
|
||||
r = pow(v, 5);
|
||||
BOOST_CHECK_EQUAL(r, boost::math::pow<5>(Real(3.25)));
|
||||
}
|
||||
BOOST_IF_CONSTEXPR(std::numeric_limits<Real>::digits10 > 11)
|
||||
{
|
||||
// (13/4)^4
|
||||
// 28561 / 256
|
||||
// 111.56640625
|
||||
r = pow(v, 4);
|
||||
BOOST_CHECK_EQUAL(r, boost::math::pow<4>(Real(3.25)));
|
||||
}
|
||||
|
||||
BOOST_IF_CONSTEXPR(std::numeric_limits<Real>::digits10 > 16)
|
||||
{
|
||||
// (13/4)^6
|
||||
// 4826809 / 4096
|
||||
// 1178.420166015625
|
||||
r = pow(v, 6);
|
||||
BOOST_CHECK_EQUAL(r, boost::math::pow<6>(Real(3.25)));
|
||||
}
|
||||
BOOST_IF_CONSTEXPR(std::numeric_limits<Real>::digits10 > 13)
|
||||
{
|
||||
// (13/4)^5
|
||||
// 371293 / 1024
|
||||
// 362.5908203125
|
||||
r = pow(v, 5);
|
||||
BOOST_CHECK_EQUAL(r, boost::math::pow<5>(Real(3.25)));
|
||||
}
|
||||
|
||||
BOOST_IF_CONSTEXPR(std::numeric_limits<Real>::digits10 > 26)
|
||||
{
|
||||
// (13/4)^10
|
||||
// 137858491849 / 1048576
|
||||
// 131472.10297489166259765625
|
||||
r = pow(v, 10);
|
||||
BOOST_CHECK_EQUAL(r, boost::math::pow<10>(Real(3.25)));
|
||||
}
|
||||
BOOST_IF_CONSTEXPR(std::numeric_limits<Real>::digits10 > 16)
|
||||
{
|
||||
// (13/4)^6
|
||||
// 4826809 / 4096
|
||||
// 1178.420166015625
|
||||
r = pow(v, 6);
|
||||
BOOST_CHECK_EQUAL(r, boost::math::pow<6>(Real(3.25)));
|
||||
}
|
||||
|
||||
BOOST_IF_CONSTEXPR(std::numeric_limits<Real>::digits10 > 38)
|
||||
{
|
||||
// (13/4)^15
|
||||
// 51185893014090757 / 1073741824
|
||||
// 47670577.665875439532101154327392578125
|
||||
r = pow(v, 15);
|
||||
BOOST_CHECK_EQUAL(r, boost::math::pow<15>(Real(3.25)));
|
||||
}
|
||||
BOOST_IF_CONSTEXPR(std::numeric_limits<Real>::digits10 > 26)
|
||||
{
|
||||
// (13/4)^10
|
||||
// 137858491849 / 1048576
|
||||
// 131472.10297489166259765625
|
||||
r = pow(v, 10);
|
||||
BOOST_CHECK_EQUAL(r, boost::math::pow<10>(Real(3.25)));
|
||||
}
|
||||
|
||||
BOOST_IF_CONSTEXPR(std::numeric_limits<Real>::digits10 > 63)
|
||||
{
|
||||
// (13/4)^25
|
||||
// 7056410014866816666030739693 / 1125899906842624
|
||||
// 6267351095760.54642313524184960016327750054188072681427001953125
|
||||
r = pow(v, 25);
|
||||
BOOST_CHECK_EQUAL(r, boost::math::pow<25>(Real(3.25)));
|
||||
BOOST_IF_CONSTEXPR(std::numeric_limits<Real>::digits10 > 38)
|
||||
{
|
||||
// (13/4)^15
|
||||
// 51185893014090757 / 1073741824
|
||||
// 47670577.665875439532101154327392578125
|
||||
r = pow(v, 15);
|
||||
BOOST_CHECK_EQUAL(r, boost::math::pow<15>(Real(3.25)));
|
||||
}
|
||||
|
||||
BOOST_IF_CONSTEXPR(std::numeric_limits<Real>::digits10 > 63)
|
||||
{
|
||||
// (13/4)^25
|
||||
// 7056410014866816666030739693 / 1125899906842624
|
||||
// 6267351095760.54642313524184960016327750054188072681427001953125
|
||||
r = pow(v, 25);
|
||||
BOOST_CHECK_EQUAL(r, boost::math::pow<25>(Real(3.25)));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1602,7 +1627,7 @@ void test_float_ops(const std::integral_constant<int, boost::multiprecision::num
|
||||
BOOST_IF_CONSTEXPR (std::numeric_limits<Real>::has_quiet_NaN)
|
||||
{
|
||||
#ifndef BOOST_MP_STANDALONE
|
||||
v = 20.25;
|
||||
v = static_cast<Real>(20.25);
|
||||
r = std::numeric_limits<Real>::quiet_NaN();
|
||||
BOOST_CHECK((boost::math::isnan)(v + r));
|
||||
BOOST_CHECK((boost::math::isnan)(r + v));
|
||||
@@ -1635,7 +1660,7 @@ void test_float_ops(const std::integral_constant<int, boost::multiprecision::num
|
||||
//
|
||||
BOOST_IF_CONSTEXPR (std::numeric_limits<Real>::has_infinity)
|
||||
{
|
||||
v = 20.25;
|
||||
v = static_cast<Real>(20.25);
|
||||
r = std::numeric_limits<Real>::infinity();
|
||||
|
||||
#ifndef BOOST_MP_STANDALONE
|
||||
@@ -3262,7 +3287,10 @@ void test()
|
||||
BOOST_CHECK_EQUAL(ac, 8 * 500L);
|
||||
ac = 8 * 500L;
|
||||
ac = ac + b + c;
|
||||
BOOST_CHECK_EQUAL(ac, 8 * 500L + 64 + 500);
|
||||
if (std::numeric_limits<Real>::digits > boost::multiprecision::msb(8 * 500L + 64 + 500))
|
||||
{
|
||||
BOOST_CHECK_EQUAL(ac, 8 * 500L + 64 + 500);
|
||||
}
|
||||
ac = a;
|
||||
ac = b + c + ac;
|
||||
BOOST_CHECK_EQUAL(ac, 8 + 64 + 500);
|
||||
@@ -3337,7 +3365,10 @@ void test()
|
||||
BOOST_CHECK_EQUAL(ac, 8 - (500 - 64));
|
||||
ac = a;
|
||||
ac -= b * c;
|
||||
BOOST_CHECK_EQUAL(ac, 8 - 500 * 64);
|
||||
if (std::numeric_limits<Real>::digits > boost::multiprecision::msb(std::abs(8 - 500 * 64)))
|
||||
{
|
||||
BOOST_CHECK_EQUAL(ac, 8 - 500 * 64);
|
||||
}
|
||||
}
|
||||
ac = a;
|
||||
ac += ac * b;
|
||||
@@ -3441,9 +3472,12 @@ void test()
|
||||
a = 20;
|
||||
b = 30;
|
||||
c = (a * b) + 22;
|
||||
BOOST_CHECK_EQUAL(c, 20 * 30 + 22);
|
||||
c = 22 + (a * b);
|
||||
BOOST_CHECK_EQUAL(c, 20 * 30 + 22);
|
||||
if (std::numeric_limits<Real>::digits > boost::multiprecision::msb(20 * 30 + 22))
|
||||
{
|
||||
BOOST_CHECK_EQUAL(c, 20 * 30 + 22);
|
||||
c = 22 + (a * b);
|
||||
BOOST_CHECK_EQUAL(c, 20 * 30 + 22);
|
||||
}
|
||||
c = 10;
|
||||
ac = a + b * c;
|
||||
BOOST_CHECK_EQUAL(ac, 20 + 30 * 10);
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Copyright 2012 John Maddock. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/multiprecision/cpp_bin_float.hpp>
|
||||
|
||||
#include "libs/multiprecision/test/test_arithmetic.hpp"
|
||||
|
||||
#if 0
|
||||
template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinExponent, Exponent MaxExponent, boost::multiprecision::expression_template_option ET>
|
||||
struct related_type<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinExponent, MaxExponent>, ET> >
|
||||
{
|
||||
typedef boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinExponent, MaxExponent>, ET> number_type;
|
||||
typedef boost::multiprecision::number<boost::multiprecision::cpp_bin_float<((std::numeric_limits<number_type>::digits / 2) > std::numeric_limits<long double>::digits ? Digits / 2 : Digits), DigitBase, Allocator, Exponent, MinExponent, MaxExponent>, ET> type;
|
||||
};
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace boost::multiprecision;
|
||||
typedef number<backends::cpp_bin_float<11, backends::digit_base_2, void, std::int16_t, -14, 15>, et_off> float16_t;
|
||||
typedef number<backends::cpp_bin_float<8, backends::digit_base_2, void, std::int16_t, -126, 127>, et_off> bfloat16_t;
|
||||
|
||||
test<float16_t>();
|
||||
test<bfloat16_t>();
|
||||
return boost::report_errors();
|
||||
}
|
||||
Reference in New Issue
Block a user