19 #include <cudf/utilities/export.hpp>
22 #include <cuda/std/cmath>
23 #include <cuda/std/limits>
24 #include <cuda/std/type_traits>
47 CUDF_ENABLE_IF(std::is_same_v<T, uint32_t> || std::is_same_v<T, uint64_t> ||
48 std::is_same_v<T, __uint128_t>)>
52 if constexpr (std::is_same_v<T, uint64_t>) {
53 return 64 - __clzll(
static_cast<int64_t
>(value));
54 }
else if constexpr (std::is_same_v<T, uint32_t>) {
55 return 32 - __clz(
static_cast<int32_t
>(value));
56 }
else if constexpr (std::is_same_v<T, __uint128_t>) {
58 auto const high_bits =
static_cast<int64_t
>(value >> 64);
59 auto const low_bits =
static_cast<int64_t
>(value);
60 return 128 - (__clzll(high_bits) +
static_cast<int>(high_bits == 0) * __clzll(low_bits));
64 if (value == 0) {
return 0; }
66 if constexpr (std::is_same_v<T, uint64_t>) {
67 return 64 - __builtin_clzll(value);
68 }
else if constexpr (std::is_same_v<T, uint32_t>) {
69 return 32 - __builtin_clz(value);
70 }
else if constexpr (std::is_same_v<T, __uint128_t>) {
72 auto const high_bits =
static_cast<uint64_t
>(value >> 64);
74 return 64 - __builtin_clzll(
static_cast<uint64_t
>(value));
76 return 128 - __builtin_clzll(high_bits);
87 template <
typename FloatingType, CUDF_ENABLE_IF(cuda::std::is_
floating_po
int_v<FloatingType>)>
93 static_assert(cuda::std::numeric_limits<FloatingType>::is_iec559,
"Assumes IEEE 754");
97 cuda::std::conditional_t<cuda::std::is_same_v<FloatingType, float>, uint32_t, uint64_t>;
101 static constexpr
int num_floating_bits =
sizeof(FloatingType) * CHAR_BIT;
103 static constexpr
int sign_bit_index = num_floating_bits - 1;
111 static constexpr
int num_significand_bits = cuda::std::numeric_limits<FloatingType>::digits;
113 static constexpr
int num_stored_mantissa_bits = num_significand_bits - 1;
121 static constexpr
int num_exponent_bits = num_floating_bits - num_stored_mantissa_bits - 1;
126 static constexpr
IntegralType exponent_mask = unshifted_exponent_mask << num_stored_mantissa_bits;
131 static constexpr
int exponent_bias = cuda::std::numeric_limits<FloatingType>::max_exponent - 1;
143 memcpy(&integer_rep, &floating,
sizeof(floating));
156 FloatingType floating;
157 memcpy(&floating, &integer,
sizeof(floating));
170 return ((integer_rep & ~sign_mask) == 0);
182 return static_cast<bool>(sign_mask & integer_rep);
198 auto significand = (integer_rep & mantissa_mask);
201 auto const exponent_bits = integer_rep & exponent_mask;
207 if (exponent_bits == 0) {
214 floating_pow2 = 1 - exponent_bias;
219 significand <<= lineup_shift;
220 floating_pow2 -= lineup_shift;
223 auto const shifted_exponent_bits = exponent_bits >> num_stored_mantissa_bits;
224 floating_pow2 =
static_cast<int>(shifted_exponent_bits) - exponent_bias;
227 significand |= understood_bit_mask;
232 int const pow2 = floating_pow2 - num_stored_mantissa_bits;
234 return {significand, pow2};
248 IntegralType integer_rep = bit_cast_to_integer(floating);
251 integer_rep |= (
IntegralType(is_negative) << sign_bit_index);
254 return bit_cast_to_floating(integer_rep);
272 auto integer_rep = bit_cast_to_integer(floating);
275 using SignedType = std::make_signed_t<IntegralType>;
276 auto exponent_bits = integer_rep & exponent_mask;
277 auto stored_pow2 =
static_cast<SignedType
>(exponent_bits >> num_stored_mantissa_bits);
283 if (stored_pow2 <= 0) {
288 auto const bit_shift = -stored_pow2 + 1;
289 if (bit_shift > num_stored_mantissa_bits) {
return 0.0; }
292 integer_rep &= (~exponent_mask);
296 integer_rep |= understood_bit_mask;
299 integer_rep >>= bit_shift;
300 }
else if (stored_pow2 >=
static_cast<SignedType
>(unshifted_exponent_mask)) {
302 return cuda::std::numeric_limits<FloatingType>::infinity();
305 exponent_bits =
static_cast<IntegralType>(stored_pow2) << num_stored_mantissa_bits;
306 integer_rep &= (~exponent_mask);
307 integer_rep |= exponent_bits;
311 return bit_cast_to_floating(integer_rep);
328 static_assert(Pow10 >= 19);
329 if constexpr (Pow10 == 19)
330 return __uint128_t(10000000000000000000ULL);
343 template <
typename T, CUDF_ENABLE_IF(cuda::std::is_
unsigned_v<T>)>
371 case 0:
return value;
372 case 1:
return value / 10U;
373 case 2:
return value / 100U;
374 case 3:
return value / 1000U;
375 case 4:
return value / 10000U;
376 case 5:
return value / 100000U;
377 case 6:
return value / 1000000U;
378 case 7:
return value / 10000000U;
379 case 8:
return value / 100000000U;
380 case 9:
return value / 1000000000U;
393 template <
typename T, CUDF_ENABLE_IF(cuda::std::is_
unsigned_v<T>)>
396 return value / ipow<uint64_t, Radix::BASE_10>(pow10);
407 template <
typename T, CUDF_ENABLE_IF(cuda::std::is_
unsigned_v<T>)>
410 return value / ipow<__uint128_t, Radix::BASE_10>(pow10);
421 template <
typename T, CUDF_ENABLE_IF(cuda::std::is_
unsigned_v<T>)>
426 case 0:
return value;
427 case 1:
return value * 10U;
428 case 2:
return value * 100U;
429 case 3:
return value * 1000U;
430 case 4:
return value * 10000U;
431 case 5:
return value * 100000U;
432 case 6:
return value * 1000000U;
433 case 7:
return value * 10000000U;
434 case 8:
return value * 100000000U;
435 case 9:
return value * 1000000000U;
448 template <
typename T, CUDF_ENABLE_IF(cuda::std::is_
unsigned_v<T>)>
451 return value * ipow<uint64_t, Radix::BASE_10>(pow10);
462 template <
typename T, CUDF_ENABLE_IF(cuda::std::is_
unsigned_v<T>)>
465 return value * ipow<__uint128_t, Radix::BASE_10>(pow10);
480 template <
typename Rep,
typename T, CUDF_ENABLE_IF(cuda::std::is_
unsigned_v<T>)>
485 if constexpr (
sizeof(Rep) <= 4) {
487 }
else if constexpr (
sizeof(Rep) <= 8) {
506 template <
typename Rep,
typename T, CUDF_ENABLE_IF(cuda::std::is_
unsigned_v<T>)>
511 if constexpr (
sizeof(Rep) <= 4) {
513 }
else if constexpr (
sizeof(Rep) <= 8) {
528 template <
typename IntegerType, CUDF_ENABLE_IF(cuda::std::is_
unsigned_v<IntegerType>)>
532 constexpr
int max_safe_bit_shift = cuda::std::numeric_limits<IntegerType>::digits - 1;
533 return (bit_shift <= max_safe_bit_shift) ? value << bit_shift
534 : cuda::std::numeric_limits<IntegerType>::max();
545 template <
typename IntegerType, CUDF_ENABLE_IF(cuda::std::is_
unsigned_v<IntegerType>)>
549 constexpr
int max_safe_bit_shift = cuda::std::numeric_limits<IntegerType>::digits - 1;
550 return (bit_shift <= max_safe_bit_shift) ? value >> bit_shift : 0;
556 template <
typename FloatingType>
559 static constexpr
bool is_double = cuda::std::is_same_v<FloatingType, double>;
562 using IntegerRep = std::conditional_t<is_double, uint64_t, uint32_t>;
565 static constexpr
auto num_significand_bits = cuda::std::numeric_limits<FloatingType>::digits;
568 using ShiftingRep = std::conditional_t<is_double, __uint128_t, uint64_t>;
601 static constexpr
int num_2s_shift_buffer_bits = is_double ? 4 : 1;
612 static constexpr
int max_digits_shift = is_double ? 18 : 9;
614 static constexpr
int max_bits_shift = max_digits_shift * 10 / 3;
618 static constexpr
auto max_digits_shift_pow =
619 multiply_power10<IntegerRep>(
IntegerRep(1), max_digits_shift);
634 template <
typename FloatingType, CUDF_ENABLE_IF(cuda::std::is_
floating_po
int_v<FloatingType>)>
635 CUDF_HOST_DEVICE cuda::std::pair<typename floating_converter<FloatingType>::IntegralType,
int>
676 int const pow2_term = 90 * pow2;
677 int const pow10_term = 299 * pow10;
678 bool const conversion_truncates =
679 (pow10_term > pow2_term) || ((pow2_term == pow10_term) && (pow2 < 0));
683 bool const is_whole_number = (cuda::std::floor(floating) == floating);
684 bool const add_half_bit = conversion_truncates && !is_whole_number;
689 integer_rep +=
static_cast<decltype(integer_rep)
>(add_half_bit);
691 return {integer_rep, pow2};
704 template <
typename Rep,
705 typename FloatingType,
722 using ShiftingRep =
typename Constants::ShiftingRep;
723 auto shifting_rep =
static_cast<ShiftingRep
>(base2_value);
730 static constexpr
int shift_up_to =
sizeof(ShiftingRep) * 8 - Constants::num_2s_shift_buffer_bits;
731 static constexpr
int shift_from = Constants::num_significand_bits + 1;
732 static constexpr
int max_init_shift = shift_up_to - shift_from;
735 using UnsignedRep = cuda::std::make_unsigned_t<Rep>;
736 if (pow2 <= max_init_shift) {
738 shifting_rep = divide_power10<ShiftingRep>(shifting_rep << pow2, pow10);
740 return static_cast<UnsignedRep
>(shifting_rep);
744 shifting_rep <<= max_init_shift;
745 pow2 -= max_init_shift;
748 while (pow10 > Constants::max_digits_shift) {
750 shifting_rep /= Constants::max_digits_shift_pow;
751 pow10 -= Constants::max_digits_shift;
754 if (pow2 <= Constants::max_bits_shift) {
756 shifting_rep = divide_power10<ShiftingRep>(shifting_rep << pow2, pow10);
759 return static_cast<UnsignedRep
>(shifting_rep);
763 shifting_rep <<= Constants::max_bits_shift;
764 pow2 -= Constants::max_bits_shift;
770 if constexpr (Constants::is_double) {
791 template <
typename Rep,
792 typename FloatingType,
803 using ShiftingRep =
typename Constants::ShiftingRep;
804 auto shifting_rep =
static_cast<ShiftingRep
>(base2_value);
807 int pow10_mag = -pow10;
808 int pow2_mag = -pow2;
811 using UnsignedRep = cuda::std::make_unsigned_t<Rep>;
812 auto final_shifts_low10s = [&]() {
815 if constexpr (Constants::is_double) {
826 if (pow10_mag <= Constants::max_digits_shift) {
return final_shifts_low10s(); }
832 static constexpr
int shift_up_to =
sizeof(ShiftingRep) * 8 - Constants::max_bits_shift;
833 static constexpr
int shift_from = Constants::num_significand_bits + 1;
834 static constexpr
int num_init_bit_shift = shift_up_to - shift_from;
837 shifting_rep <<= num_init_bit_shift;
838 pow2_mag += num_init_bit_shift;
843 shifting_rep *= Constants::max_digits_shift_pow;
844 pow10_mag -= Constants::max_digits_shift;
847 if (pow2_mag <= Constants::max_bits_shift) {
849 shifting_rep >>= pow2_mag;
855 return multiply_power10<UnsignedRep>(
static_cast<UnsignedRep
>(shifting_rep), pow10_mag);
859 shifting_rep >>= Constants::max_bits_shift;
860 pow2_mag -= Constants::max_bits_shift;
861 }
while (pow10_mag > Constants::max_digits_shift);
864 return final_shifts_low10s();
877 template <
typename Rep,
878 typename FloatingType,
892 using UnsignedRep = cuda::std::make_unsigned_t<Rep>;
901 }
else if (pow10 > 0) {
906 return static_cast<UnsignedRep
>(divide_power10<decltype(shifted)>(shifted, pow10));
908 return shift_to_decimal_pospow<Rep, FloatingType>(base2_value, pow2, pow10);
914 return multiply_power10<UnsignedRep>(shifted, -pow10);
916 return shift_to_decimal_negpow<Rep, FloatingType>(base2_value, pow2, pow10);
929 template <
typename Rep,
930 typename FloatingType,
937 auto const integer_rep = converter::bit_cast_to_integer(floating);
938 if (converter::is_zero(integer_rep)) {
return 0; }
941 auto const is_negative = converter::get_is_negative(integer_rep);
942 auto const [significand, floating_pow2] = converter::get_significand_and_pow2(integer_rep);
945 auto const pow10 =
static_cast<int>(scale);
946 auto const [base2_value, pow2] =
950 auto const magnitude =
951 convert_floating_to_integral_shifting<Rep, FloatingType>(base2_value, pow10, pow2);
955 auto const signed_magnitude =
static_cast<Rep
>(magnitude);
956 return is_negative ? -signed_magnitude : signed_magnitude;
968 template <
typename FloatingType,
977 using ShiftingRep =
typename Constants::ShiftingRep;
982 static constexpr
int shift_up_to =
sizeof(ShiftingRep) * 8 - Constants::max_bits_shift;
984 int const num_init_bit_shift = shift_up_to - shift_from;
985 int pow2 = -num_init_bit_shift;
988 ShiftingRep shifting_rep;
989 if constexpr (
sizeof(ShiftingRep) <
sizeof(DecimalRep)) {
991 decimal_rep = (pow2 >= 0) ? (decimal_rep >> pow2) : (decimal_rep << -pow2);
992 shifting_rep =
static_cast<ShiftingRep
>(decimal_rep);
995 shifting_rep =
static_cast<ShiftingRep
>(decimal_rep);
996 shifting_rep = (pow2 >= 0) ? (shifting_rep >> pow2) : (shifting_rep << -pow2);
1000 while (pow10 > Constants::max_digits_shift) {
1002 shifting_rep *= Constants::max_digits_shift_pow;
1003 pow10 -= Constants::max_digits_shift;
1006 shifting_rep >>= Constants::max_bits_shift;
1007 pow2 += Constants::max_bits_shift;
1012 if constexpr (Constants::is_double) {
1019 return std::pair{shifting_rep, pow2};
1031 template <
typename FloatingType,
1032 typename DecimalRep,
1040 using ShiftingRep =
typename Constants::ShiftingRep;
1045 static constexpr
int shift_up_to =
sizeof(ShiftingRep) * 8 - Constants::num_2s_shift_buffer_bits;
1047 int const num_init_bit_shift = shift_up_to - shift_from;
1048 int pow2 = -num_init_bit_shift;
1051 ShiftingRep shifting_rep;
1052 if constexpr (
sizeof(ShiftingRep) <
sizeof(DecimalRep)) {
1054 decimal_rep = (pow2 >= 0) ? (decimal_rep >> pow2) : (decimal_rep << -pow2);
1055 shifting_rep =
static_cast<ShiftingRep
>(decimal_rep);
1058 shifting_rep =
static_cast<ShiftingRep
>(decimal_rep);
1059 shifting_rep = (pow2 >= 0) ? (shifting_rep >> pow2) : (shifting_rep << -pow2);
1063 int pow10_mag = -pow10;
1066 while (pow10_mag > Constants::max_digits_shift) {
1068 shifting_rep /= Constants::max_digits_shift_pow;
1069 pow10_mag -= Constants::max_digits_shift;
1072 shifting_rep <<= Constants::max_bits_shift;
1073 pow2 -= Constants::max_bits_shift;
1079 if constexpr (Constants::is_double) {
1086 return std::pair{shifting_rep, pow2};
1098 template <
typename FloatingType,
1105 bool const is_negative = (value < 0);
1108 using UnsignedType = cuda::std::make_unsigned_t<Rep>;
1109 auto const unsigned_value = [&]() -> UnsignedType {
1111 if (value == cuda::std::numeric_limits<Rep>::min()) {
return static_cast<UnsignedType
>(value); }
1114 if constexpr (cuda::std::is_same_v<Rep, __int128_t>) {
1115 return static_cast<UnsignedType
>(is_negative ? -value : value);
1117 return cuda::std::abs(value);
1122 auto const [mantissa, pow2] = [&]() {
1123 auto const pow10 =
static_cast<int32_t
>(scale);
1125 return shift_to_binary_pospow<FloatingType>(unsigned_value, pow10);
1127 return shift_to_binary_negpow<FloatingType>(unsigned_value, pow10);
1132 if (mantissa == 0) {
return FloatingType(0.0f); }
1135 auto const floating =
static_cast<FloatingType
>(mantissa);
1139 auto const magnitude = converter::add_pow2(floating, pow2);
1140 return converter::set_is_negative(magnitude, is_negative);
CUDF_HOST_DEVICE cuda::std::make_unsigned_t< Rep > shift_to_decimal_pospow(typename shifting_constants< FloatingType >::IntegerRep const base2_value, int pow2, int pow10)
Perform base-2 -> base-10 fixed-point conversion for pow10 > 0.
constexpr CUDF_HOST_DEVICE T multiply_power10_64bit(T value, int pow10)
Multiply by a power of 10 that fits within a 64bit integer.
CUDF_HOST_DEVICE auto shift_to_binary_pospow(DecimalRep decimal_rep, int pow10)
Perform base-10 -> base-2 fixed-point conversion for pow10 > 0.
CUDF_HOST_DEVICE IntegerType guarded_right_shift(IntegerType value, int bit_shift)
Perform a bit-shift right, guarding against undefined behavior.
CUDF_HOST_DEVICE T divide_power10_32bit(T value, int pow10)
Divide by a power of 10 that fits within a 32bit integer.
constexpr CUDF_HOST_DEVICE T multiply_power10(T value, int pow10)
Multiply an integer by a power of 10.
constexpr CUDF_HOST_DEVICE T divide_power10_128bit(T value, int pow10)
Divide by a power of 10 that fits within a 128bit integer.
CUDF_HOST_DEVICE cuda::std::make_unsigned_t< Rep > convert_floating_to_integral_shifting(typename floating_converter< FloatingType >::IntegralType base2_value, int pow10, int pow2)
Perform base-2 -> base-10 fixed-point conversion.
CUDF_HOST_DEVICE auto shift_to_binary_negpow(DecimalRep decimal_rep, int const pow10)
Perform base-10 -> base-2 fixed-point conversion for pow10 < 0.
constexpr CUDF_HOST_DEVICE T multiply_power10_128bit(T value, int pow10)
Multiply by a power of 10 that fits within a 128bit integer.
CUDF_HOST_DEVICE FloatingType convert_integral_to_floating(Rep const &value, scale_type const &scale)
Perform integer decimal -> floating-point conversion.
CUDF_HOST_DEVICE IntegerType guarded_left_shift(IntegerType value, int bit_shift)
Perform a bit-shift left, guarding against undefined behavior.
CUDF_HOST_DEVICE cuda::std::pair< typename floating_converter< FloatingType >::IntegralType, int > add_half_if_truncates(FloatingType floating, typename floating_converter< FloatingType >::IntegralType integer_rep, int pow2, int pow10)
Add half a bit to integer rep of floating point if conversion causes truncation.
constexpr __uint128_t large_power_of_10()
Recursively calculate a signed large power of 10 (>= 10^19) that can only be stored in an 128bit inte...
constexpr CUDF_HOST_DEVICE T divide_power10(T value, int pow10)
Divide an integer by a power of 10.
constexpr CUDF_HOST_DEVICE T multiply_power10_32bit(T value, int pow10)
Multiply by a power of 10 that fits within a 32bit integer.
CUDF_HOST_DEVICE int count_significant_bits(T value)
Determine the number of significant bits in an integer.
CUDF_HOST_DEVICE cuda::std::make_unsigned_t< Rep > shift_to_decimal_negpow(typename shifting_constants< FloatingType >::IntegerRep base2_value, int pow2, int pow10)
Perform base-2 -> base-10 fixed-point conversion for pow10 < 0.
CUDF_HOST_DEVICE T divide_power10_64bit(T value, int pow10)
Divide by a power of 10 that fits within a 64bit integer.
CUDF_HOST_DEVICE Rep convert_floating_to_integral(FloatingType const &floating, scale_type const &scale)
Perform floating-point -> integer decimal conversion.
scale_type
The scale type for fixed_point.
#define CUDF_ENABLE_IF(...)
Convenience macro for SFINAE as an unnamed template parameter.
fixed_point and supporting types
Helper struct for getting and setting the components of a floating-point value.
static CUDF_HOST_DEVICE FloatingType bit_cast_to_floating(IntegralType integer)
Reinterpret the bits of an integer as floating-point value.
static CUDF_HOST_DEVICE FloatingType add_pow2(FloatingType floating, int pow2)
Adds to the base-2 exponent of a floating-point number.
static CUDF_HOST_DEVICE std::pair< IntegralType, int > get_significand_and_pow2(IntegralType integer_rep)
Extracts the significand and exponent of a bit-casted floating-point number, shifted for denormals.
static CUDF_HOST_DEVICE bool is_zero(IntegralType integer_rep)
Checks whether the bit-casted floating-point value is +/-0.
static CUDF_HOST_DEVICE IntegralType bit_cast_to_integer(FloatingType floating)
Reinterpret the bits of a floating-point value as an integer.
static CUDF_HOST_DEVICE FloatingType set_is_negative(FloatingType floating, bool is_negative)
Sets the sign bit of a floating-point number.
cuda::std::conditional_t< cuda::std::is_same_v< FloatingType, float >, uint32_t, uint64_t > IntegralType
Unsigned int type with same size as floating type.
static CUDF_HOST_DEVICE bool get_is_negative(IntegralType integer_rep)
Extracts the sign bit of a bit-casted floating-point number.
Helper struct with common constants needed by the floating <--> decimal conversions.
std::conditional_t< is_double, __uint128_t, uint64_t > ShiftingRep
Shift data back and forth in space of a type with 2x the starting bits, to give us enough room.
std::conditional_t< is_double, uint64_t, uint32_t > IntegerRep
Integer type that can hold the value of the significand.
#define CUDF_HOST_DEVICE
Indicates that the function or method is usable on host and device.