88#include < boost/decimal/bid_conversion.hpp>
99#include < boost/decimal/detail/config.hpp>
1010#include < boost/decimal/detail/concepts.hpp>
11+ #include < boost/decimal/detail/emulated128.hpp>
1112
1213#ifndef BOOST_DECIMAL_BUILD_MODULE
1314#include < cstdint>
@@ -425,6 +426,9 @@ template <typename DecimalType = decimal32_fast>
425426constexpr auto from_dpd_d32 (std::uint32_t dpd) noexcept
426427 BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType)
427428{
429+ static_assert (std::is_same<DecimalType, decimal32>::value || std::is_same<DecimalType, decimal32_fast>::value,
430+ " Target decimal type must be 32-bits" );
431+
428432 // First we check for non-finite values
429433 // Since they are in the same initial format as BID it's easy to check with our existing masks
430434 if ((dpd & detail::d32_inf_mask) == detail::d32_inf_mask)
@@ -618,6 +622,9 @@ template <typename DecimalType = decimal64_fast>
618622constexpr auto from_dpd_d64 (std::uint64_t dpd) noexcept
619623 BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, DecimalType)
620624{
625+ static_assert (std::is_same<DecimalType, decimal64>::value || std::is_same<DecimalType, decimal64_fast>::value,
626+ " Target decimal type must be 64-bits" );
627+
621628 // First we check for non-finite values
622629 // Since they are in the same initial format as BID it's easy to check with our existing masks
623630 if ((dpd & detail::d64_inf_mask) == detail::d64_inf_mask)
@@ -696,6 +703,201 @@ constexpr auto from_dpd_d64(std::uint64_t dpd) noexcept
696703 return DecimalType{significand, exp, sign};
697704}
698705
706+ template <typename DecimalType>
707+ constexpr auto to_dpd_d128 (DecimalType val) noexcept
708+ BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, DecimalType, detail::uint128)
709+ {
710+ static_assert (std::is_same<DecimalType, decimal128>::value ||
711+ std::is_same<DecimalType, decimal128_fast>::value, " The input must be a 128-bit decimal type" );
712+
713+ // In the non-finite cases the encodings are the same
714+ // 3.5.2.a and 3.5.2.b
715+ if (!isfinite (val))
716+ {
717+ return to_bid (val);
718+ }
719+
720+ const auto sign {val.isneg ()};
721+ const auto exp {val.unbiased_exponent ()};
722+ const auto significand {val.full_significand ()};
723+
724+ detail::uint128 dpd {};
725+
726+ // Set the sign bit as applicable
727+ if (sign)
728+ {
729+ dpd.high |= detail::d128_sign_mask.high ;
730+ }
731+
732+ constexpr int num_digits {std::numeric_limits<DecimalType>::digits10};
733+ std::uint8_t d[static_cast <std::size_t >(num_digits)] {};
734+ auto temp_sig {significand};
735+ for (int i = num_digits - 1 ; i >= 0 ; --i)
736+ {
737+ d[i] = static_cast <std::uint8_t >(temp_sig % 10U );
738+ temp_sig /= 10U ;
739+ }
740+ BOOST_DECIMAL_ASSERT (d[0 ] >= 0 && d[0 ] <= 9 );
741+ BOOST_DECIMAL_ASSERT (temp_sig == 0 );
742+
743+ constexpr std::uint64_t leading_two_exp_bits_mask {0b11000000000000 };
744+ const auto leading_two_bits {(exp & leading_two_exp_bits_mask) >> 12U };
745+ constexpr std::uint64_t trailing_exp_bits_mask {0b00111111111111 };
746+ const auto trailing_exp_bits {(exp & trailing_exp_bits_mask)};
747+
748+ std::uint64_t combination_field_bits {};
749+
750+ // Now based on what the value of d[0] and the leading bits of exp are we can set the value of the combination field
751+ // See 3.5.2.c.1
752+ // If d0 is 8 or 9 then we follow section i
753+ if (d[0 ] >= 8 )
754+ {
755+ const auto d0_is_nine {d[0 ] == 9 };
756+ switch (leading_two_bits)
757+ {
758+ case 0U :
759+ combination_field_bits = d0_is_nine ? 0b11001 : 0b11000 ;
760+ break ;
761+ case 1U :
762+ combination_field_bits = d0_is_nine ? 0b11011 : 0b11010 ;
763+ break ;
764+ case 2U :
765+ combination_field_bits = d0_is_nine ? 0b11101 : 0b11100 ;
766+ break ;
767+ // LCOV_EXCL_START
768+ default :
769+ BOOST_DECIMAL_UNREACHABLE;
770+ // LCOV_EXCL_STOP
771+ }
772+ }
773+ // If d0 is 0 to 7 then we follow section II
774+ else
775+ {
776+ // In here the value of d[0] = 4*G2 + 2*G3 + G4
777+ const auto d0_mask {static_cast <std::uint64_t >(d[0 ])};
778+ switch (leading_two_bits)
779+ {
780+ case 0U :
781+ // 00XXX
782+ combination_field_bits |= d0_mask;
783+ break ;
784+ case 1U :
785+ // 01XXX
786+ combination_field_bits = 0b01000 ;
787+ combination_field_bits |= d0_mask;
788+ break ;
789+ case 2U :
790+ // 10XXX
791+ combination_field_bits = 0b10000 ;
792+ combination_field_bits |= d0_mask;
793+ break ;
794+ // LCOV_EXCL_START
795+ default :
796+ BOOST_DECIMAL_UNREACHABLE;
797+ // LCOV_EXCL_STOP
798+ }
799+ }
800+
801+ // Write the now know combination field and trailing exp bits to the result
802+ dpd.high |= (combination_field_bits << 58U );
803+ dpd.high |= (trailing_exp_bits << 46U );
804+
805+ // Now we have to encode all 11 of the declets
806+ int offset {10 };
807+ for (std::size_t i {1 }; i < num_digits - 1 ; i += 3U )
808+ {
809+ const auto declet {static_cast <detail::uint128>(detail::encode_dpd (d[i], d[i + 1 ], d[i + 2 ]))};
810+ dpd |= detail::uint128 (declet << (10 * offset));
811+ --offset;
812+ }
813+
814+ return dpd;
815+ }
816+
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[static_cast <std::size_t >(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 - 1 ) - i));
896+ }
897+
898+ return DecimalType{significand, exp, sign};
899+ }
900+
699901constexpr auto to_dpd (decimal32 val) noexcept -> std::uint32_t
700902{
701903 return to_dpd_d32 (val);
@@ -706,16 +908,26 @@ constexpr auto to_dpd(decimal32_fast val) noexcept -> std::uint32_t
706908 return to_dpd_d32 (val);
707909}
708910
709- constexpr auto to_dpd (decimal64 val) -> std::uint64_t
911+ constexpr auto to_dpd (decimal64 val) noexcept -> std::uint64_t
710912{
711913 return to_dpd_d64 (val);
712914}
713915
714- constexpr auto to_dpd (decimal64_fast val) -> std::uint64_t
916+ constexpr auto to_dpd (decimal64_fast val) noexcept -> std::uint64_t
715917{
716918 return to_dpd_d64 (val);
717919}
718920
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+
719931template <typename DecimalType>
720932constexpr auto to_dpd (DecimalType val) noexcept
721933{
@@ -737,6 +949,25 @@ constexpr auto from_dpd(std::uint64_t bits) noexcept
737949 return from_dpd_d64<DecimalType>(bits);
738950}
739951
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+
740971} // namespace decimal
741972} // namespace boost
742973
0 commit comments