Skip to content

Commit e4bc095

Browse files
committed
Implement and refactor mixed type division for 32 bits
1 parent b7bd826 commit e4bc095

File tree

4 files changed

+169
-54
lines changed

4 files changed

+169
-54
lines changed

include/boost/decimal/decimal32.hpp

Lines changed: 4 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include <boost/decimal/detail/add_impl.hpp>
3636
#include <boost/decimal/detail/sub_impl.hpp>
3737
#include <boost/decimal/detail/mul_impl.hpp>
38+
#include <boost/decimal/detail/div_impl.hpp>
3839

3940
#ifndef BOOST_DECIMAL_BUILD_MODULE
4041

@@ -170,8 +171,6 @@ BOOST_DECIMAL_EXPORT class decimal32 final // NOLINT(cppcoreguidelines-special-m
170171
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE TargetType, BOOST_DECIMAL_DECIMAL_FLOATING_TYPE Decimal>
171172
friend constexpr auto to_decimal(Decimal val) noexcept -> TargetType;
172173

173-
friend constexpr auto generic_div_impl(detail::decimal32_components lhs, detail::decimal32_components rhs,
174-
detail::decimal32_components& q) noexcept -> void;
175174
friend constexpr auto div_impl(decimal32 lhs, decimal32 rhs, decimal32& q, decimal32& r) noexcept -> void;
176175
friend constexpr auto mod_impl(decimal32 lhs, decimal32 rhs, const decimal32& q, decimal32& r) noexcept -> void;
177176

@@ -1680,43 +1679,6 @@ constexpr auto decimal32::operator*=(Decimal rhs) noexcept
16801679
return *this;
16811680
}
16821681

1683-
constexpr auto generic_div_impl(detail::decimal32_components lhs, detail::decimal32_components rhs,
1684-
detail::decimal32_components& q) noexcept -> void
1685-
{
1686-
bool sign {lhs.sign != rhs.sign};
1687-
1688-
// If rhs is greater than we need to offset the significands to get the correct values
1689-
// e.g. 4/8 is 0 but 40/8 yields 5 in integer maths
1690-
const auto big_sig_lhs {static_cast<std::uint64_t>(lhs.sig) * detail::powers_of_10[detail::precision]};
1691-
lhs.exp -= detail::precision;
1692-
1693-
auto res_sig {big_sig_lhs / static_cast<std::uint64_t>(rhs.sig)};
1694-
auto res_exp {lhs.exp - rhs.exp};
1695-
1696-
const auto sig_dig {detail::num_digits(res_sig)};
1697-
1698-
if (sig_dig > std::numeric_limits<std::uint32_t>::digits10)
1699-
{
1700-
res_sig /= detail::pow10(static_cast<std::uint64_t>(sig_dig - std::numeric_limits<std::uint32_t>::digits10));
1701-
res_exp += sig_dig - std::numeric_limits<std::uint32_t>::digits10;
1702-
}
1703-
1704-
const auto res_sig_32 {static_cast<std::uint32_t>(res_sig)};
1705-
1706-
#ifdef BOOST_DECIMAL_DEBUG
1707-
std::cerr << "\nres sig: " << res_sig_32
1708-
<< "\nres exp: " << res_exp << std::endl;
1709-
#endif
1710-
1711-
if (res_sig_32 == 0)
1712-
{
1713-
sign = false;
1714-
}
1715-
1716-
// Let the constructor handle shrinking it back down and rounding correctly
1717-
q = detail::decimal32_components{res_sig_32, res_exp, sign};
1718-
}
1719-
17201682
constexpr auto div_impl(decimal32 lhs, decimal32 rhs, decimal32& q, decimal32& r) noexcept -> void
17211683
{
17221684
// Check pre-conditions
@@ -1783,7 +1745,7 @@ constexpr auto div_impl(decimal32 lhs, decimal32 rhs, decimal32& q, decimal32& r
17831745
detail::decimal32_components rhs_components {sig_rhs, exp_rhs, rhs.isneg()};
17841746
detail::decimal32_components q_components {};
17851747

1786-
generic_div_impl(lhs_components, rhs_components, q_components);
1748+
detail::generic_div_impl(lhs_components, rhs_components, q_components);
17871749

17881750
q = decimal32(q_components.sig, q_components.exp, q_components.sign);
17891751
}
@@ -1845,7 +1807,7 @@ constexpr auto operator/(decimal32 lhs, Integer rhs) noexcept
18451807
detail::decimal32_components rhs_components {detail::shrink_significand(detail::make_positive_unsigned(rhs), exp_rhs), exp_rhs, rhs < 0};
18461808
detail::decimal32_components q_components {};
18471809

1848-
generic_div_impl(lhs_components, rhs_components, q_components);
1810+
detail::generic_div_impl(lhs_components, rhs_components, q_components);
18491811

18501812
return decimal32(q_components.sig, q_components.exp, q_components.sign);
18511813
}
@@ -1888,7 +1850,7 @@ constexpr auto operator/(Integer lhs, decimal32 rhs) noexcept
18881850
detail::decimal32_components rhs_components {sig_rhs, exp_rhs, rhs.isneg()};
18891851
detail::decimal32_components q_components {};
18901852

1891-
generic_div_impl(lhs_components, rhs_components, q_components);
1853+
detail::generic_div_impl(lhs_components, rhs_components, q_components);
18921854

18931855
return decimal32(q_components.sig, q_components.exp, q_components.sign);
18941856
}

include/boost/decimal/decimal32_fast.hpp

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <boost/decimal/detail/add_impl.hpp>
1414
#include <boost/decimal/detail/sub_impl.hpp>
1515
#include <boost/decimal/detail/mul_impl.hpp>
16+
#include <boost/decimal/detail/div_impl.hpp>
1617
#include <boost/decimal/detail/ryu/ryu_generic_128.hpp>
1718
#include <limits>
1819
#include <cstdint>
@@ -239,6 +240,14 @@ class decimal32_fast final
239240
friend constexpr auto operator*(Integer lhs, decimal32_fast rhs) noexcept
240241
BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_fast);
241242

243+
template <typename Integer>
244+
friend constexpr auto operator/(decimal32_fast lhs, Integer rhs) noexcept
245+
BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_fast);
246+
247+
template <typename Integer>
248+
friend constexpr auto operator/(Integer lhs, decimal32_fast rhs) noexcept
249+
BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_fast);
250+
242251
// Compound operators
243252
constexpr auto operator+=(decimal32_fast rhs) noexcept -> decimal32_fast&;
244253
constexpr auto operator-=(decimal32_fast rhs) noexcept -> decimal32_fast&;
@@ -972,6 +981,93 @@ constexpr auto operator/(decimal32_fast lhs, decimal32_fast rhs) noexcept -> dec
972981
return q;
973982
}
974983

984+
template <typename Integer>
985+
constexpr auto operator/(decimal32_fast lhs, Integer rhs) noexcept
986+
BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_fast)
987+
{
988+
// Check pre-conditions
989+
constexpr decimal32_fast zero {0, 0};
990+
constexpr decimal32_fast nan {direct_init(detail::d32_fast_qnan, UINT8_C(0), false)};
991+
constexpr decimal32_fast inf {direct_init(detail::d32_fast_inf, UINT8_C(0), false)};
992+
993+
const bool sign {lhs.isneg() != (rhs < 0)};
994+
995+
const auto lhs_fp {fpclassify(lhs)};
996+
997+
switch (lhs_fp)
998+
{
999+
case FP_NAN:
1000+
return nan;
1001+
case FP_INFINITE:
1002+
return inf;
1003+
case FP_ZERO:
1004+
return sign ? -zero : zero;
1005+
default:
1006+
static_cast<void>(lhs);
1007+
}
1008+
1009+
if (rhs == 0)
1010+
{
1011+
return sign ? -inf : inf;
1012+
}
1013+
1014+
auto sig_lhs {lhs.full_significand()};
1015+
auto exp_lhs {lhs.biased_exponent()};
1016+
detail::normalize(sig_lhs, exp_lhs);
1017+
1018+
const detail::decimal32_fast_components lhs_components {sig_lhs, exp_lhs, lhs.isneg()};
1019+
std::int32_t exp_rhs {};
1020+
const detail::decimal32_fast_components rhs_components {detail::shrink_significand<std::uint_fast32_t>(detail::make_positive_unsigned(rhs), exp_rhs), exp_rhs, rhs < 0};
1021+
detail::decimal32_fast_components q_components {};
1022+
1023+
detail::generic_div_impl(lhs_components, rhs_components, q_components);
1024+
1025+
return {q_components.sig, q_components.exp, q_components.sign};
1026+
}
1027+
1028+
template <typename Integer>
1029+
constexpr auto operator/(Integer lhs, decimal32_fast rhs) noexcept
1030+
BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_fast)
1031+
{
1032+
// Check pre-conditions
1033+
constexpr decimal32_fast zero {0, 0};
1034+
constexpr decimal32_fast nan {direct_init(detail::d32_fast_qnan, UINT8_C(0), false)};
1035+
constexpr decimal32_fast inf {direct_init(detail::d32_fast_inf, UINT8_C(0), false)};
1036+
1037+
const bool sign {(lhs < 0) != rhs.isneg()};
1038+
1039+
const auto rhs_fp {fpclassify(rhs)};
1040+
1041+
if (rhs_fp == FP_NAN)
1042+
{
1043+
return nan;
1044+
}
1045+
1046+
switch (rhs_fp)
1047+
{
1048+
case FP_INFINITE:
1049+
return sign ? -zero : zero;
1050+
case FP_ZERO:
1051+
return sign ? -inf : inf;
1052+
default:
1053+
static_cast<void>(lhs);
1054+
}
1055+
1056+
auto sig_rhs {rhs.full_significand()};
1057+
auto exp_rhs {rhs.biased_exponent()};
1058+
detail::normalize(sig_rhs, exp_rhs);
1059+
1060+
std::int32_t lhs_exp {};
1061+
const auto lhs_sig {detail::make_positive_unsigned(detail::shrink_significand<std::uint_fast32_t>(lhs, lhs_exp))};
1062+
const detail::decimal32_fast_components lhs_components {lhs_sig, lhs_exp, lhs < 0};
1063+
const detail::decimal32_fast_components rhs_components {sig_rhs, exp_rhs, rhs.isneg()};
1064+
detail::decimal32_fast_components q_components {};
1065+
1066+
detail::generic_div_impl(lhs_components, rhs_components, q_components);
1067+
1068+
return {q_components.sig, q_components.exp, q_components.sign};
1069+
}
1070+
9751071
constexpr auto operator%(decimal32_fast lhs, decimal32_fast rhs) noexcept -> decimal32_fast
9761072
{
9771073
decimal32_fast q {};
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2023 - 2024 Matt Borland
2+
// Distributed under the Boost Software License, Version 1.0.
3+
// https://www.boost.org/LICENSE_1_0.txt
4+
5+
#ifndef BOOST_DECIMAL_DETAIL_DIV_IMPL_HPP
6+
#define BOOST_DECIMAL_DETAIL_DIV_IMPL_HPP
7+
8+
#ifndef BOOST_DECIMAL_BUILD_MODULE
9+
#include <limits>
10+
#include <cstdint>
11+
#endif
12+
13+
namespace boost {
14+
namespace decimal {
15+
namespace detail {
16+
17+
template <typename T>
18+
constexpr auto generic_div_impl(const T& lhs, const T& rhs, T& q) noexcept -> void
19+
{
20+
bool sign {lhs.sign != rhs.sign};
21+
22+
// If rhs is greater than we need to offset the significands to get the correct values
23+
// e.g. 4/8 is 0 but 40/8 yields 5 in integer maths
24+
const auto big_sig_lhs {static_cast<std::uint64_t>(lhs.sig) * detail::pow10(detail::precision)};
25+
26+
auto res_sig {big_sig_lhs / static_cast<std::uint64_t>(rhs.sig)};
27+
auto res_exp {(lhs.exp - detail::precision) - rhs.exp};
28+
29+
const auto sig_dig {detail::num_digits(res_sig)};
30+
31+
if (sig_dig > std::numeric_limits<std::uint32_t>::digits10)
32+
{
33+
res_sig /= detail::pow10(static_cast<std::uint64_t>(sig_dig - std::numeric_limits<std::uint32_t>::digits10));
34+
res_exp += sig_dig - std::numeric_limits<std::uint32_t>::digits10;
35+
}
36+
37+
const auto res_sig_32 {static_cast<std::uint32_t>(res_sig)};
38+
39+
#ifdef BOOST_DECIMAL_DEBUG
40+
std::cerr << "\nres sig: " << res_sig_32
41+
<< "\nres exp: " << res_exp << std::endl;
42+
#endif
43+
44+
if (res_sig_32 == 0)
45+
{
46+
sign = false;
47+
}
48+
49+
// Let the constructor handle shrinking it back down and rounding correctly
50+
q = T{res_sig_32, res_exp, sign};
51+
}
52+
53+
} // namespace detail
54+
} // namespace decimal
55+
} // namespace boost
56+
57+
#endif //BOOST_DECIMAL_DETAIL_DIV_IMPL_HPP

test/random_decimal32_fast_math.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -946,30 +946,30 @@ int main()
946946
random_division(0L, 5'000L);
947947
random_division(0LL, 5'000LL);
948948
random_division(0, sqrt_int_max);
949-
//random_mixed_division(0, 5'000);
950-
//random_mixed_division(0L, 5'000L);
951-
//random_mixed_division(0LL, 5'000LL);
952-
//random_mixed_division(0, sqrt_int_max);
949+
random_mixed_division(0, 5'000);
950+
random_mixed_division(0L, 5'000L);
951+
random_mixed_division(0LL, 5'000LL);
952+
random_mixed_division(0, sqrt_int_max);
953953

954954
// Only negative values
955955
random_division(-5'000, 0);
956956
random_division(-5'000L, 0L);
957957
random_division(-5'000LL, 0LL);
958958
random_division(-sqrt_int_max, 0);
959-
//random_mixed_division(-5'000, 0);
960-
//random_mixed_division(-5'000L, 0L);
961-
//random_mixed_division(-5'000LL, 0LL);
962-
//random_mixed_division(-sqrt_int_max, 0);
959+
random_mixed_division(-5'000, 0);
960+
random_mixed_division(-5'000L, 0L);
961+
random_mixed_division(-5'000LL, 0LL);
962+
random_mixed_division(-sqrt_int_max, 0);
963963

964964
// Mixed values
965965
random_division(-5'000, 5'000);
966966
random_division(-5'000L, 5'000L);
967967
random_division(-5'000LL, 5'000LL);
968968
random_division(-sqrt_int_max, sqrt_int_max);
969-
//random_mixed_division(-5'000, 5'000);
970-
//random_mixed_division(-5'000L, 5'000L);
971-
//random_mixed_division(-5'000LL, 5'000LL);
972-
//random_mixed_division(-sqrt_int_max, sqrt_int_max);
969+
random_mixed_division(-5'000, 5'000);
970+
random_mixed_division(-5'000L, 5'000L);
971+
random_mixed_division(-5'000LL, 5'000LL);
972+
random_mixed_division(-sqrt_int_max, sqrt_int_max);
973973

974974
/*
975975
// Bitwise operators

0 commit comments

Comments
 (0)