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:
jzmaddock
2023-12-16 09:21:29 +00:00
committed by GitHub
parent a32f657409
commit 20187736b3
5 changed files with 362 additions and 128 deletions
+60 -12
View File
@@ -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);
+2
View File
@@ -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 : ]
+122
View File
@@ -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
View File
@@ -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);
+28
View File
@@ -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();
}