Skip to content

Commit 347a3aa

Browse files
committed
Add 128-bit from_dpd conversion overload
1 parent bcecb9f commit 347a3aa

File tree

1 file changed

+115
-2
lines changed

1 file changed

+115
-2
lines changed

include/boost/decimal/dpd_conversion.hpp

Lines changed: 115 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,90 @@ constexpr auto to_dpd_d128(DecimalType val) noexcept
814814
return dpd;
815815
}
816816

817+
template <typename DecimalType = decimal128_fast>
818+
constexpr auto from_dpd_d128(detail::uint128 dpd) noexcept
819+
BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType)
820+
{
821+
static_assert(std::is_same<DecimalType, decimal128>::value || std::is_same<DecimalType, decimal128_fast>::value,
822+
"Target decimal type must be 128-bits");
823+
824+
if ((dpd & detail::d128_inf_mask) == detail::d128_inf_mask)
825+
{
826+
if ((dpd & detail::d128_snan_mask) == detail::d128_snan_mask)
827+
{
828+
return std::numeric_limits<DecimalType>::signaling_NaN();
829+
}
830+
else if ((dpd & detail::d128_nan_mask) == detail::d128_nan_mask)
831+
{
832+
return std::numeric_limits<DecimalType>::quiet_NaN();
833+
}
834+
else
835+
{
836+
return std::numeric_limits<DecimalType>::infinity();
837+
}
838+
}
839+
840+
// The bit lengths are the same as used in the standard bid format
841+
const auto sign {(dpd.high & detail::d128_sign_mask.high) != 0};
842+
const auto combination_field_bits {(dpd.high & detail::d128_combination_field_mask.high) >> 58U};
843+
const auto exponent_field_bits {(dpd.high & detail::d128_exponent_mask.high) >> 46U};
844+
auto significand_bits {(dpd & detail::d128_significand_mask)};
845+
846+
// Case 1: 3.5.2.c.1.i
847+
// Combination field bits are 110XX or 11110X
848+
std::uint64_t d0 {};
849+
std::uint64_t leading_biased_exp_bits {};
850+
if (combination_field_bits >= 0b11000)
851+
{
852+
// d0 = 8 + G4
853+
// Must be equal to 8 or 9
854+
d0 = 8U + (combination_field_bits & 0b00001);
855+
BOOST_DECIMAL_ASSERT(d0 == 8 || d0 == 9);
856+
857+
// leading exp bits are 2*G2 + G3
858+
// Must be equal to 0, 1 or 2
859+
leading_biased_exp_bits = 2U * ((combination_field_bits & 0b00100) >> 2U) + ((combination_field_bits & 0b00010) >> 1U);
860+
BOOST_DECIMAL_ASSERT(leading_biased_exp_bits <= 2U);
861+
}
862+
// Case 2: 3.5.2.c.1.ii
863+
// Combination field bits are 0XXXX or 10XXX
864+
else
865+
{
866+
// d0 = 4 * G2 + 2 * G3 + G4
867+
// Must be in the range 0-7
868+
d0 = combination_field_bits & 0b00111;
869+
BOOST_DECIMAL_ASSERT(d0 <= 7);
870+
871+
// Leading exp bits are 2 * G0 + G1
872+
// Must be equal to 0, 1 or 2
873+
leading_biased_exp_bits = (combination_field_bits & 0b11000) >> 3U;
874+
BOOST_DECIMAL_ASSERT(leading_biased_exp_bits <= 2U);
875+
}
876+
877+
// Now that we have the bits we can calculate the exponents value
878+
const auto complete_exp {(leading_biased_exp_bits << 12U) + exponent_field_bits};
879+
const auto exp {static_cast<std::int32_t>(complete_exp) - detail::bias_v<DecimalType>};
880+
881+
// We can now decode the remainder of the significand to recover the value
882+
constexpr auto num_digits {std::numeric_limits<DecimalType>::digits10};
883+
std::uint8_t digits[num_digits] {};
884+
digits[0] = static_cast<std::uint8_t>(d0);
885+
for (int i = num_digits - 1; i > 0; i -= 3)
886+
{
887+
const auto declet_bits {static_cast<std::uint32_t>(significand_bits & 0b1111111111)};
888+
significand_bits >>= 10U;
889+
detail::decode_dpd(declet_bits, digits[i], digits[i - 1], digits[i - 2]);
890+
}
891+
892+
detail::uint128 significand {};
893+
for (int i {}; i < num_digits; ++i)
894+
{
895+
significand += static_cast<detail::uint128>(digits[i]) * detail::pow10(static_cast<detail::uint128>(num_digits - i));
896+
}
897+
898+
return DecimalType{significand, exp, sign};
899+
}
900+
817901
constexpr auto to_dpd(decimal32 val) noexcept -> std::uint32_t
818902
{
819903
return to_dpd_d32(val);
@@ -824,16 +908,26 @@ constexpr auto to_dpd(decimal32_fast val) noexcept -> std::uint32_t
824908
return to_dpd_d32(val);
825909
}
826910

827-
constexpr auto to_dpd(decimal64 val) -> std::uint64_t
911+
constexpr auto to_dpd(decimal64 val) noexcept -> std::uint64_t
828912
{
829913
return to_dpd_d64(val);
830914
}
831915

832-
constexpr auto to_dpd(decimal64_fast val) -> std::uint64_t
916+
constexpr auto to_dpd(decimal64_fast val) noexcept -> std::uint64_t
833917
{
834918
return to_dpd_d64(val);
835919
}
836920

921+
constexpr auto to_dpd(decimal128 val) noexcept -> detail::uint128
922+
{
923+
return to_dpd_d128(val);
924+
}
925+
926+
constexpr auto to_dpd(decimal128_fast val) noexcept -> detail::uint128
927+
{
928+
return to_dpd_d128(val);
929+
}
930+
837931
template <typename DecimalType>
838932
constexpr auto to_dpd(DecimalType val) noexcept
839933
{
@@ -855,6 +949,25 @@ constexpr auto from_dpd(std::uint64_t bits) noexcept
855949
return from_dpd_d64<DecimalType>(bits);
856950
}
857951

952+
template <typename DecimalType = decimal128_fast>
953+
constexpr auto from_dpd(detail::uint128 bits) noexcept
954+
BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType)
955+
{
956+
return from_dpd_d128<DecimalType>(bits);
957+
}
958+
959+
#ifdef BOOST_DECIMAL_HAS_INT128
960+
961+
template <typename DecimalType = decimal128_fast>
962+
constexpr auto from_dpd(detail::uint128_t bits) noexcept
963+
BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType)
964+
{
965+
const detail::uint128 converted_bits {bits};
966+
return from_dpd_d128<DecimalType>(converted_bits);
967+
}
968+
969+
#endif // BOOST_DECIMAL_HAS_INT128
970+
858971
} // namespace decimal
859972
} // namespace boost
860973

0 commit comments

Comments
 (0)