Skip to content

Commit 3253fb4

Browse files
committed
[#17]:svarga:feature, add compound assignment operators and improve 128-bit support
1 parent 0ba0d57 commit 3253fb4

1 file changed

Lines changed: 60 additions & 40 deletions

File tree

include/decimal.hpp

Lines changed: 60 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -191,22 +191,22 @@ namespace math::bid {
191191
if (exponent < -6176 || exponent > 6111) throw std::out_of_range("Exponent out of Decimal128 range.");
192192
if (significand > max_significand) return zero;
193193
const std::uint64_t biased_exponent = static_cast<std::uint64_t>(exponent) + bias;
194-
if ((significand.w[1] >> 49) == 0) return {significand.w[0], (significand.w[1] & 0x0001FFFFFFFFFFFFull) | ((biased_exponent & 0x3fffull) << 49)}; // small finite branch: coefficient < 2^113
194+
if ((significand.w[1] >> 49) == 0) return {significand.w[0], (significand.w[1] & 0x0001FFFFFFFFFFFFull) | ((biased_exponent & 0x3fffull) << 49)};
195+
// small finite branch: coefficient < 2^113
195196
return { significand.w[0], ((significand.w[1] & 0x00007FFFFFFFFFFFull)) | ((biased_exponent & 0x3fffull) << 47) | (0x3ull << 61)}; // large finite branch: coefficient has implicit leading 100...
196197
}
197198
}
198199

199200
namespace math {
200201
using uint128_t = BID_UINT128;
201-
202202
template <class T> struct bid_t {
203203
bid_t(T value) : value(value){}
204-
operator T(){ return value; }
204+
operator T() const { return value; }
205205
T value;
206206
};
207207
template <class T> struct dpd_t {
208208
dpd_t(T value) : value(value){}
209-
operator T(){ return value; }
209+
operator T() const { return value; }
210210
T value;
211211
};
212212
template <class T> struct decimal_t;
@@ -221,7 +221,6 @@ namespace math {
221221
template<typename T> T str2bid(std::string_view);
222222
template<typename T> T str2bid(const std::string&);
223223
template<typename T> std::string bid2str(T);
224-
template<typename T> std::pair<T,int16_t> decompose(T arg);
225224
template<typename T> T identity(T arg) { return arg; };
226225

227226
template<> uint32_t bid2dpd(uint32_t bid){ return __bid_to_dpd32(bid); }
@@ -239,7 +238,7 @@ namespace math {
239238
template<> uint64_t bid2dpd(uint64_t bid){ return __bid_to_dpd64(bid); }
240239
template<> uint64_t dpd2bid(uint64_t dpd){ return __bid_dpd_to_bid64(dpd); }
241240
template<> uint64_t uint2bid(uint64_t significand, int exponent){ return bid::uint64_to_bid64(significand, exponent); }
242-
template<> uint64_t zero(){ return 0x31A0000000000000ULL; }
241+
template<> uint64_t zero(){ return 0x31C0000000000000ULL; }
243242
template<> long double bid2float<uint64_t, long double>(uint64_t bid){ unsigned int flags; return __bid64_to_binary80(bid, 0, &flags); }
244243
template<> uint64_t float2bid<float, uint64_t>(float bin){ unsigned int flags; return __binary32_to_bid64(bin, 0, &flags); }
245244
template<> uint64_t float2bid<double, uint64_t>(double bin){ unsigned int flags; return __binary64_to_bid64(bin, 0, &flags); }
@@ -262,55 +261,51 @@ namespace math {
262261
}
263262

264263
// operator defintions
265-
#define sigma_unary_operator(_type, _op, _bid_fname) decimal_t<_type> operator _op() { return decimal_t<_type>(_bid_fname(value)); }
266-
#define sigma_arithmetic_operator(_type, _op, _bid_fname) inline decimal_t<_type> operator _op(decimal_t<_type> lhs, decimal_t<_type> rhs) {\
264+
#define sigma_arithmetic_operator(_type, _op, _bid_fname) inline decimal_t<_type> operator _op(decimal_t<_type> lhs, decimal_t<_type> rhs) { \
267265
unsigned int flags; return decimal_t<_type>::set(_bid_fname(lhs.value, rhs.value, 0, &flags)); }
268266
#define sigma_comparison_operator(_type, _op, _bid_fname) inline bool operator _op(decimal_t<_type> lhs, decimal_t<_type> rhs) {\
269267
unsigned int flags; return _bid_fname(lhs.value, rhs.value, &flags); }
270268

271-
#define sigma_decimal_class(size, value_t, float_t) \
272-
template <> struct decimal_t<value_t> { \
273-
decimal_t() : value(impl::zero<value_t>()){} \
274-
decimal_t(value_t significand, int exponent) : value(impl::uint2bid<value_t>(significand, exponent)){} \
275-
decimal_t(float_t bin) : value(impl::float2bid<float_t,value_t>(bin)){} \
276-
decimal_t(dpd_t<value_t> dpd) : value(impl::dpd2bid<value_t>(dpd)){} \
277-
decimal_t(const char* ptr): value(impl::str2bid<value_t>(std::string_view{ptr})){} \
278-
decimal_t(std::string_view str): value(impl::str2bid<value_t>(str)){} \
279-
decimal_t(const std::string& str): value(impl::str2bid<value_t>(str)){} \
280-
static decimal_t<value_t> from(float bin){ return decimal_t<value_t>(impl::float2bid<float, value_t>(bin));} \
281-
static decimal_t<value_t> from(double bin){ return decimal_t<value_t>(impl::float2bid<double, value_t>(bin));} \
282-
static decimal_t<value_t> from(long double bin){ return decimal_t<value_t>(impl::float2bid<long double, value_t>(bin));} \
283-
static decimal_t<value_t> set(value_t value){ decimal_t decimal; decimal.value = value; return decimal;} \
284-
explicit operator dpd_t<value_t>() const { return impl::bid2dpd<value_t>(this->value); } \
285-
explicit operator bid_t<value_t>() const { return value; } \
286-
explicit operator float_t() const { return impl::bid2float<value_t, float_t>(this->value); } \
287-
operator std::string() const { return impl::bid2str(value); } \
288-
operator std::pair<value_t, int16_t>() const { return impl::decompose(value); } \
289-
decimal_t<value_t> operator +() const { return *this; } \
290-
sigma_unary_operator(uint##size##_t, +, impl::identity); \
291-
sigma_unary_operator(uint##size##_t, -, __bid##size##_negate); \
292-
value_t value; \
269+
#define sigma_decimal_class(size, value_t, float_t) \
270+
template <> struct decimal_t<value_t> { \
271+
decimal_t() : value(impl::zero<value_t>()){} \
272+
decimal_t(value_t significand, int exponent) : value(impl::uint2bid<value_t>(significand, exponent)){} \
273+
decimal_t(float_t bin) : value(impl::float2bid<float_t,value_t>(bin)){} \
274+
decimal_t(dpd_t<value_t> dpd) : value(impl::dpd2bid<value_t>(dpd)){} \
275+
decimal_t(const char* ptr): value(impl::str2bid<value_t>(std::string_view{ptr})){} \
276+
decimal_t(std::string_view str): value(impl::str2bid<value_t>(str)){} \
277+
decimal_t(const std::string& str): value(impl::str2bid<value_t>(str)){} \
278+
static decimal_t<value_t> from(float bin){ return set(impl::float2bid<float, value_t>(bin));} \
279+
static decimal_t<value_t> from(double bin){ return set(impl::float2bid<double, value_t>(bin));} \
280+
static decimal_t<value_t> from(long double bin){ return set(impl::float2bid<long double, value_t>(bin));} \
281+
static decimal_t<value_t> set(value_t value){ decimal_t decimal; decimal.value = value; return decimal;} \
282+
explicit operator dpd_t<value_t>() const { return impl::bid2dpd<value_t>(this->value); } \
283+
explicit operator bid_t<value_t>() const { return value; } \
284+
explicit operator float_t() const { return impl::bid2float<value_t, float_t>(this->value); } \
285+
operator std::string() const { return impl::bid2str(value); } \
286+
decimal_t<value_t>& operator +=(const decimal_t& rhs) {unsigned int flags; value = __bid##size##_add(value, rhs.value, 0, &flags); return *this; } \
287+
decimal_t<value_t>& operator -=(const decimal_t& rhs) {unsigned int flags; value = __bid##size##_sub(value, rhs.value, 0, &flags); return *this; } \
288+
decimal_t<value_t> operator +() const { return *this; } \
289+
decimal_t<value_t> operator -() const { decimal_t<value_t> out; out.value = __bid##size##_negate(value); return out; } \
290+
value_t value; \
293291
}
294292

295293
sigma_decimal_class(32, uint32_t, double);
296294
sigma_decimal_class(64, uint64_t, long double);
297295
sigma_decimal_class(128, uint128_t, long double);
298-
299296
// operator combinations
300297
#define sigma_external_operators(_bit_size_) \
301298
sigma_arithmetic_operator(uint##_bit_size_##_t, +, __bid##_bit_size_##_add); sigma_arithmetic_operator(uint##_bit_size_##_t, -, __bid##_bit_size_##_sub); \
302299
sigma_arithmetic_operator(uint##_bit_size_##_t, *, __bid##_bit_size_##_mul); sigma_arithmetic_operator(uint##_bit_size_##_t, /, __bid##_bit_size_##_div); \
303300
sigma_comparison_operator(uint##_bit_size_##_t, ==, __bid##_bit_size_##_quiet_equal); sigma_comparison_operator(uint##_bit_size_##_t, !=, __bid##_bit_size_##_quiet_not_equal); \
304301
sigma_comparison_operator(uint##_bit_size_##_t, <, __bid##_bit_size_##_quiet_less); sigma_comparison_operator(uint##_bit_size_##_t, >, __bid##_bit_size_##_quiet_greater); \
305302
sigma_comparison_operator(uint##_bit_size_##_t, <=, __bid##_bit_size_##_quiet_less_equal); sigma_comparison_operator(uint##_bit_size_##_t, >=, __bid##_bit_size_##_quiet_greater_equal);
306-
307303
// operator instatiations for various bit sizes
308304
sigma_external_operators(32); sigma_external_operators(64); sigma_external_operators(128);
309305
#undef sigma_external_operators
310306
#undef sigma_decimal_class
311307
#undef sigma_comparison_operator
312308
#undef sigma_arithmetic_operator
313-
#undef sigma_unary_operator
314309

315310
#define sigma_decimal_literal(type, literal) inline decimal_t<type> operator""##literal(const char* characters) { \
316311
std::string data(characters); \
@@ -325,16 +320,35 @@ namespace math {
325320
}
326321
#undef sigma_decimal_literal
327322
// begin utilities:
328-
template <typename bid_t>
329-
std::tuple<bool, bid_t, int16_t> decompose(decimal_t<bid_t> bid){
323+
template <typename bid_t> std::tuple<bool, bid_t, int16_t> decompose(decimal_t<bid_t> bid){
330324
auto [discriminant, mantissa, exponent] = bid::decompose(bid.value);
331325
switch(discriminant) {
332326
case bid::category::nan: throw std::runtime_error("nan");
333-
case bid::category::pinf: return std::make_tuple(false, std::numeric_limits<bid_t>::max(), std::numeric_limits<uint16_t>::max());
334-
case bid::category::ninf: return std::make_tuple(true, std::numeric_limits<bid_t>::max(), std::numeric_limits<uint16_t>::max());
327+
case bid::category::pinf: return std::make_tuple(false, std::numeric_limits<bid_t>::max(), std::numeric_limits<int16_t>::max());
328+
case bid::category::ninf: return std::make_tuple(true, std::numeric_limits<bid_t>::max(), std::numeric_limits<int16_t>::max());
335329
case bid::category::negative: return std::make_tuple(true, mantissa, exponent);
336330
case bid::category::positive: return std::make_tuple(false, mantissa, exponent);
337331
}
332+
#if defined(__cpp_lib_unreachable) && __cpp_lib_unreachable >= 202202L
333+
std::unreachable();
334+
#else
335+
throw std::runtime_error("invalid decimal category");
336+
#endif
337+
}
338+
template <> inline std::tuple<bool, BID_UINT128, int16_t> decompose(decimal_t<BID_UINT128> bid) {
339+
auto [discriminant, mantissa, exponent] = bid::decompose(bid.value);
340+
switch (discriminant) {
341+
case bid::category::nan: throw std::runtime_error("nan");
342+
case bid::category::pinf: return std::make_tuple(false, BID_UINT128{{~0ull, ~0ull}}, std::numeric_limits<int16_t>::max());
343+
case bid::category::ninf: return std::make_tuple(true, BID_UINT128{{~0ull, ~0ull}}, std::numeric_limits<int16_t>::max());
344+
case bid::category::negative: return std::make_tuple(true, to_bid128(mantissa), exponent);
345+
case bid::category::positive: return std::make_tuple(false, to_bid128(mantissa), exponent);
346+
}
347+
#if defined(__cpp_lib_unreachable) && __cpp_lib_unreachable >= 202202L
348+
std::unreachable();
349+
#else
350+
throw std::runtime_error("invalid decimal category");
351+
#endif
338352
}
339353
template <typename bid_t> bid_t mantissa(decimal_t<bid_t> bid) {
340354
auto [discriminant, mantissa, exponent] = bid::decompose(bid.value);
@@ -343,8 +357,16 @@ namespace math {
343357
case bid::category::pinf: throw std::runtime_error("inexact exception: +inf");
344358
case bid::category::ninf: throw std::runtime_error("inexact exception: -inf");
345359
case bid::category::negative: throw std::runtime_error("attempting to convert negative value to unsigned");
346-
case bid::category::positive: return mantissa;
360+
case bid::category::positive:
361+
if constexpr (std::is_same_v<bid_t, BID_UINT128>)
362+
return to_bid128(mantissa);
363+
else return mantissa;
347364
}
365+
#if defined(__cpp_lib_unreachable) && __cpp_lib_unreachable >= 202202L
366+
std::unreachable();
367+
#else
368+
throw std::runtime_error("invalid decimal category");
369+
#endif
348370
}
349371
// end utilities
350372
}
@@ -407,8 +429,6 @@ namespace math {
407429
#undef sigma_binary_op
408430
}
409431
// constants
410-
411-
412432
namespace math {
413433
template <typename integral_type> struct constants;
414434
template <> struct constants<uint32_t>{ // 7 digit precision

0 commit comments

Comments
 (0)