Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
2c27725
Add simplified u256 add impl
mborland Dec 17, 2025
31deee4
Add intrinsic powered impl
mborland Dec 17, 2025
8f7c92b
Add second u256 addition impl
mborland Dec 17, 2025
5294424
Add i256_sub method
mborland Dec 17, 2025
35b21fa
Add signed 256 x 256 addition
mborland Dec 17, 2025
e9620b1
Add intrinsic powered sub
mborland Dec 17, 2025
b38025a
Add second intrin powered sub
mborland Dec 17, 2025
0d4fd38
Add new decimal128_t addition impl with new paths
mborland Dec 17, 2025
d7a5bd1
Add compound mul operator
mborland Dec 17, 2025
cf2da34
Add operator u256 > u128
mborland Dec 17, 2025
238ac78
Add pretty printer for u256
mborland Dec 17, 2025
5a7b55d
Add proper constructor for uint128_t
mborland Dec 17, 2025
1b7801d
Add handling of double negative path
mborland Dec 17, 2025
cfe2a44
Add potential fast path for non-normalized addition and subtraction
mborland Dec 17, 2025
068849b
Fix 256 bit powers of 10
mborland Dec 17, 2025
e9bac59
Add additional testing of pre generated powers of ten
mborland Dec 17, 2025
d419085
Add additional test case
mborland Dec 17, 2025
cf8f156
Use new addition method
mborland Dec 17, 2025
544c25a
Fix pow10 generation
mborland Dec 17, 2025
8f356c7
More tests
mborland Dec 17, 2025
76a03de
Fix missing sub borrow instrinsic
mborland Dec 17, 2025
b5f0865
Fix missing variable
mborland Dec 17, 2025
a20dbc2
Explicitly construct u256 for u128
mborland Jan 12, 2026
4f30023
Expand the significands prior to addition
mborland Jan 12, 2026
c2f5652
Add cheaper accessor function
mborland Jan 12, 2026
9ac3a41
Explicitly test for zero
mborland Jan 12, 2026
d113ffe
Test seemingly trivial value
mborland Jan 12, 2026
6b0cac8
Fix subtraction word order
mborland Jan 12, 2026
ffcaafd
Improve use of intrinsics
mborland Jan 12, 2026
57e593e
Remove unneeded functions
mborland Jan 12, 2026
6a8dbde
Ignore impossible sign conversion warning
mborland Jan 12, 2026
f8a8e6f
Test existence of builtin
mborland Jan 12, 2026
464e3fb
Remove unused function
mborland Jan 12, 2026
fa8b2d6
Add detection of i386 intrin
mborland Jan 13, 2026
aae9a8c
Fix macros being detected
mborland Jan 13, 2026
ad01581
Implement subcll workaround for i386
mborland Jan 13, 2026
9dc581a
Add GDB printer for u256 internal type
mborland Jan 13, 2026
df7d977
Add testing failure from 32 bit platforms
mborland Jan 13, 2026
7237e34
Fix byte order
mborland Jan 13, 2026
627d376
Add special handling for u256 divided by a single word
mborland Jan 13, 2026
87fc521
Remove branch testing for zero
mborland Jan 13, 2026
cd3cc9c
Use and test new impl with decimal_fast128_t
mborland Jan 13, 2026
6fc97f9
Implement and test subtraction
mborland Jan 13, 2026
3e923c5
Use new function for mixed type add and sub
mborland Jan 13, 2026
72c5c5a
Use new function for fast math mixed types
mborland Jan 13, 2026
0659137
Fix mixed nans handling
mborland Jan 13, 2026
653aa3c
Ignore GCC 7 warning
mborland Jan 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions extra/decimal_printer_gdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,27 @@ def children(self):
yield ('sign_', self.val['sign_'])


class U256Printer:
"""Pretty printer for u256 internal type"""

def __init__(self, val):
self.val = val

def to_string(self):
try:
bytes = self.val['bytes']
byte0 = int(bytes[3]) & 0xFFFFFFFFFFFFFFFF
byte1 = int(bytes[2]) & 0xFFFFFFFFFFFFFFFF
byte2 = int(bytes[1]) & 0xFFFFFFFFFFFFFFFF
byte3 = int(bytes[0]) & 0xFFFFFFFFFFFFFFFF

value = (byte0 << 192) | (byte1 << 128) | (byte2 << 64) | byte3
return f"{value:,}"
except Exception as e:
return f"<invalid u256: {e}>"



def build_pretty_printer():
"""Build and return the pretty printer collection"""
pp = gdb.printing.RegexpCollectionPrettyPrinter("boost_decimal")
Expand All @@ -164,6 +185,11 @@ def build_pretty_printer():
r'^(const )?(boost::decimal::)?decimal_fast128_t( &| \*)?$',
DecimalFast128Printer)

# Debug internal types
pp.add_printer('u256',
r'^(const )?(boost::decimal::detail::)?u256( &| \*)?$',
U256Printer)

return pp


Expand Down
51 changes: 51 additions & 0 deletions extra/decimal_printer_lldb.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,26 @@ def decimal_fast128_summary(valobj, internal_dict):
except Exception as e:
return f"<invalid decimal_fast128_t: {e}>"

def u256_summary(valobj, internal_dict):
"""
Custom summary for u256 detail type
Displays in decimal notation
"""

try:
val = valobj.GetNonSyntheticValue()

bytes = val.GetChildMemberWithName("bytes")
b0 = bytes.GetChildAtIndex(0).GetValueAsUnsigned()
b1 = bytes.GetChildAtIndex(1).GetValueAsUnsigned()
b2 = bytes.GetChildAtIndex(2).GetValueAsUnsigned()
b3 = bytes.GetChildAtIndex(3).GetValueAsUnsigned()

value = (b3 << 192) | (b2 << 128) | (b1 << 64) | b0
return f"{value:,}"
except Exception as e:
return f"<invalid u256: {e}>"

def __lldb_init_module(debugger, internal_dict):
decimal32_pattern = r"^(const )?(boost::decimal::decimal32_t|(\w+::)*decimal32_t)( &| \*)?$"
decimal64_pattern = r"^(const )?(boost::decimal::decimal64_t|(\w+::)*decimal64_t)( &| \*)?$"
Expand All @@ -118,6 +138,8 @@ def __lldb_init_module(debugger, internal_dict):
decimal_fast64_pattern = r"^(const )?(boost::decimal::decimal_fast64_t|(\w+::)*decimal_fast64_t)( &| \*)?$"
decimal_fast128_pattern = r"^(const )?(boost::decimal::decimal_fast128_t|(\w+::)*decimal_fast128_t)( &| \*)?$"

u256_pattern = r"^(const )?(boost::decimal::detail::u256|(\w+::)*u256)( &| \*)?$"

debugger.HandleCommand(
f'type summary add -x "{decimal32_pattern}" -e -F decimal_printer_lldb.decimal32_summary'
)
Expand Down Expand Up @@ -172,6 +194,13 @@ def __lldb_init_module(debugger, internal_dict):

print("decimal_fast128_t printer loaded successfully")

debugger.HandleCommand(
f'type summary add -x "{u256_pattern}" -e -F decimal_printer_lldb.u256_summary'
)
debugger.HandleCommand(
f'type synthetic add -x "{u256_pattern}" -l decimal_printer_lldb.u256SyntheticProvider'
)

class DecimalSyntheticProvider:
def __init__(self, valobj, internal_dict):
self.valobj = valobj
Expand Down Expand Up @@ -228,3 +257,25 @@ def update(self):
def has_children(self):
return True

class u256SyntheticProvider:
def __init__(self, valobj, internal_dict):
self.valobj = valobj

def num_children(self):
return 1

def get_child_index(self, name):
if name == "bytes":
return 0
return -1

def get_child_at_index(self, index):
if index == 0:
return self.valobj.GetChildMemberWithName("bytes")
return None

def update(self):
pass

def has_children(self):
return True
82 changes: 25 additions & 57 deletions include/boost/decimal/decimal128_t.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1708,24 +1708,20 @@ constexpr auto operator+(const decimal128_t& lhs, const decimal128_t& rhs) noexc
}
#endif

auto lhs_sig {lhs.full_significand()};
auto lhs_exp {lhs.biased_exponent()};
detail::expand_significand<decimal128_t>(lhs_sig, lhs_exp);

auto rhs_sig {rhs.full_significand()};
auto rhs_exp {rhs.biased_exponent()};
detail::expand_significand<decimal128_t>(rhs_sig, rhs_exp);
auto lhs_components {lhs.to_components()};
detail::expand_significand<decimal128_t>(lhs_components.sig, lhs_components.exp);
auto rhs_components {rhs.to_components()};
detail::expand_significand<decimal128_t>(rhs_components.sig, rhs_components.exp);

return detail::d128_add_impl<decimal128_t>(lhs_sig, lhs_exp, lhs.isneg(),
rhs_sig, rhs_exp, rhs.isneg(),
abs(lhs) > abs(rhs));
return detail::d128_add_impl_new<decimal128_t>(lhs_components, rhs_components);
}

template <typename Integer>
constexpr auto operator+(const decimal128_t lhs, const Integer rhs) noexcept
BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal128_t)
{
using exp_type = decimal128_t::biased_exponent_type;
using sig_type = decimal128_t::significand_type;

#ifndef BOOST_DECIMAL_FAST_MATH
if (not_finite(lhs))
Expand All @@ -1734,19 +1730,15 @@ constexpr auto operator+(const decimal128_t lhs, const Integer rhs) noexcept
}
#endif

auto sig_rhs {static_cast<int128::uint128_t>(detail::make_positive_unsigned(rhs))};
bool abs_lhs_bigger {abs(lhs) > sig_rhs};

auto sig_lhs {lhs.full_significand()};
auto exp_lhs {lhs.biased_exponent()};
detail::expand_significand<decimal128_t>(sig_lhs, exp_lhs);
auto lhs_components {lhs.to_components()};
detail::expand_significand<decimal128_t>(lhs_components.sig, lhs_components.exp);

auto positive_rhs {static_cast<sig_type>(detail::make_positive_unsigned(rhs))};
exp_type exp_rhs {0};
detail::normalize<decimal128_t>(sig_rhs, exp_rhs);
detail::normalize<decimal128_t>(positive_rhs, exp_rhs);
const detail::decimal128_t_components rhs_components {positive_rhs, exp_rhs, rhs < 0};

return detail::d128_add_impl<decimal128_t>(sig_lhs, exp_lhs, lhs.isneg(),
sig_rhs, exp_rhs, (rhs < 0),
abs_lhs_bigger);
return detail::d128_add_impl_new<decimal128_t>(lhs_components, rhs_components);
}

template <typename Integer>
Expand All @@ -1771,25 +1763,21 @@ constexpr auto operator-(const decimal128_t& lhs, const decimal128_t& rhs) noexc
}
#endif

auto sig_lhs {lhs.full_significand()};
auto exp_lhs {lhs.biased_exponent()};
detail::expand_significand<decimal128_t>(sig_lhs, exp_lhs);

auto sig_rhs {rhs.full_significand()};
auto exp_rhs {rhs.biased_exponent()};
detail::expand_significand<decimal128_t>(sig_rhs, exp_rhs);
auto lhs_components {lhs.to_components()};
detail::expand_significand<decimal128_t>(lhs_components.sig, lhs_components.exp);
auto rhs_components {rhs.to_components()};
detail::expand_significand<decimal128_t>(rhs_components.sig, rhs_components.exp);
rhs_components.sign = !rhs_components.sign;

return detail::d128_add_impl<decimal128_t>(
sig_lhs, exp_lhs, lhs.isneg(),
sig_rhs, exp_rhs, !rhs.isneg(),
abs(lhs) > abs(rhs));
return detail::d128_add_impl_new<decimal128_t>(lhs_components, rhs_components);
}

template <typename Integer>
constexpr auto operator-(const decimal128_t lhs, const Integer rhs) noexcept
BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal128_t)
{
using exp_type = decimal128_t::biased_exponent_type;
using sig_type = decimal128_t::significand_type;

#ifndef BOOST_DECIMAL_FAST_MATH
if (not_finite(lhs))
Expand All @@ -1798,49 +1786,29 @@ constexpr auto operator-(const decimal128_t lhs, const Integer rhs) noexcept
}
#endif

auto sig_rhs {static_cast<int128::uint128_t>(detail::make_positive_unsigned(rhs))};
const bool abs_lhs_bigger {abs(lhs) > sig_rhs};

auto sig_lhs {lhs.full_significand()};
auto exp_lhs {lhs.biased_exponent()};
detail::expand_significand<decimal128_t>(sig_lhs, exp_lhs);
auto lhs_components {lhs.to_components()};
detail::expand_significand<decimal128_t>(lhs_components.sig, lhs_components.exp);

auto sig_rhs {static_cast<sig_type>(detail::make_positive_unsigned(rhs))};
exp_type exp_rhs {0};
detail::normalize<decimal128_t>(sig_rhs, exp_rhs);
const detail::decimal128_t_components rhs_components {sig_rhs, exp_rhs, !(rhs < 0)};

return detail::d128_add_impl<decimal128_t>(
sig_lhs, exp_lhs, lhs.isneg(),
sig_rhs, exp_rhs, !(rhs < 0),
abs_lhs_bigger);
return detail::d128_add_impl_new<decimal128_t>(lhs_components, rhs_components);
}

template <typename Integer>
constexpr auto operator-(const Integer lhs, const decimal128_t rhs) noexcept
BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal128_t)
{
using exp_type = decimal128_t::biased_exponent_type;

#ifndef BOOST_DECIMAL_FAST_MATH
if (not_finite(rhs))
{
return detail::check_non_finite(rhs);
}
#endif

auto sig_lhs {static_cast<int128::uint128_t>(detail::make_positive_unsigned(lhs))};
const bool abs_lhs_bigger {sig_lhs > abs(rhs)};

exp_type exp_lhs {0};
detail::normalize<decimal128_t>(sig_lhs, exp_lhs);

auto sig_rhs {rhs.full_significand()};
auto exp_rhs {rhs.biased_exponent()};
detail::expand_significand<decimal128_t>(sig_rhs, exp_rhs);

return detail::d128_add_impl<decimal128_t>(
sig_lhs, exp_lhs, (lhs < 0),
sig_rhs, exp_rhs, !rhs.isneg(),
abs_lhs_bigger);
return -rhs + lhs;
}

constexpr auto operator*(const decimal128_t& lhs, const decimal128_t& rhs) noexcept -> decimal128_t
Expand Down
47 changes: 14 additions & 33 deletions include/boost/decimal/decimal_fast128_t.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,9 @@ BOOST_DECIMAL_EXPORT class alignas(16) decimal_fast128_t final
template <typename Decimal>
friend constexpr Decimal detail::check_non_finite(Decimal x) noexcept;

template <typename ReturnType, typename T>
friend constexpr auto detail::d128_add_impl_new(const T& lhs, const T& rhs) noexcept -> ReturnType;

public:
constexpr decimal_fast128_t() noexcept = default;

Expand Down Expand Up @@ -1032,17 +1035,15 @@ constexpr auto operator+(const decimal_fast128_t& lhs, const decimal_fast128_t&
}
#endif

return detail::d128_add_impl<decimal_fast128_t>(
lhs.significand_, lhs.biased_exponent(), lhs.sign_,
rhs.significand_, rhs.biased_exponent(), rhs.sign_,
(abs(lhs) > abs(rhs)));
return detail::d128_add_impl_new<decimal_fast128_t>(lhs, rhs);
}

template <typename Integer>
constexpr auto operator+(const decimal_fast128_t& lhs, const Integer rhs) noexcept
BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast128_t)
{
using exp_type = decimal_fast128_t::biased_exponent_type;
using sig_type = decimal_fast128_t::significand_type;

#ifndef BOOST_DECIMAL_FAST_MATH
if (not_finite(lhs))
Expand All @@ -1051,15 +1052,12 @@ constexpr auto operator+(const decimal_fast128_t& lhs, const Integer rhs) noexce
}
#endif

auto sig_rhs {static_cast<int128::uint128_t>(detail::make_positive_unsigned(rhs))};
bool abs_lhs_bigger {abs(lhs) > sig_rhs};

auto sig_rhs {static_cast<sig_type>(detail::make_positive_unsigned(rhs))};
exp_type exp_rhs {0};
detail::normalize<decimal_fast128_t>(sig_rhs, exp_rhs);
const detail::decimal_fast128_t_components rhs_components {sig_rhs, exp_rhs, rhs < 0};

return detail::d128_add_impl<decimal_fast128_t>(lhs.significand_, lhs.biased_exponent(), lhs.sign_,
sig_rhs, exp_rhs, (rhs < 0),
abs_lhs_bigger);
return detail::d128_add_impl_new<decimal_fast128_t>(lhs.to_components(), rhs_components);
}

template <typename Integer>
Expand All @@ -1083,17 +1081,15 @@ constexpr auto operator-(const decimal_fast128_t& lhs, const decimal_fast128_t&
}
#endif

return detail::d128_add_impl<decimal_fast128_t>(
lhs.significand_, lhs.biased_exponent(), lhs.sign_,
rhs.significand_, rhs.biased_exponent(), !rhs.sign_,
abs(lhs) > abs(rhs));
return detail::d128_add_impl_new<decimal_fast128_t>(lhs, -rhs);
}

template <typename Integer>
constexpr auto operator-(const decimal_fast128_t& lhs, const Integer rhs) noexcept
BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast128_t)
{
using exp_type = decimal_fast128_t::biased_exponent_type;
using sig_type = decimal_fast128_t::significand_type;

#ifndef BOOST_DECIMAL_FAST_MATH
if (not_finite(lhs))
Expand All @@ -1102,41 +1098,26 @@ constexpr auto operator-(const decimal_fast128_t& lhs, const Integer rhs) noexce
}
#endif

auto sig_rhs {static_cast<int128::uint128_t>(detail::make_positive_unsigned(rhs))};
const bool abs_lhs_bigger {abs(lhs) > sig_rhs};

auto sig_rhs {static_cast<sig_type>(detail::make_positive_unsigned(rhs))};
exp_type exp_rhs {0};
detail::normalize<decimal_fast128_t>(sig_rhs, exp_rhs);
const detail::decimal_fast128_t_components rhs_components {sig_rhs, exp_rhs, !(rhs < 0)};

return detail::d128_add_impl<decimal_fast128_t>(
lhs.significand_, lhs.biased_exponent(), lhs.sign_,
sig_rhs, exp_rhs, !(rhs < 0),
abs_lhs_bigger);
return detail::d128_add_impl_new<decimal_fast128_t>(lhs.to_components(), rhs_components);
}

template <typename Integer>
constexpr auto operator-(const Integer lhs, const decimal_fast128_t& rhs) noexcept
BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal_fast128_t)
{
using exp_type = decimal_fast128_t::biased_exponent_type;

#ifndef BOOST_DECIMAL_FAST_MATH
if (not_finite(rhs))
{
return detail::check_non_finite(rhs);
}
#endif

auto sig_lhs {static_cast<int128::uint128_t>(detail::make_positive_unsigned(lhs))};
const bool abs_lhs_bigger {sig_lhs > abs(rhs)};

exp_type exp_lhs {0};
detail::normalize<decimal_fast128_t>(sig_lhs, exp_lhs);

return detail::d128_add_impl<decimal_fast128_t>(
sig_lhs, exp_lhs, (lhs < 0),
rhs.significand_, rhs.biased_exponent(), !rhs.sign_,
abs_lhs_bigger);
return -rhs + lhs;
}

constexpr auto operator*(const decimal_fast128_t& lhs, const decimal_fast128_t& rhs) noexcept -> decimal_fast128_t
Expand Down
Loading