| 726 | |
| 727 | template<typename T> |
| 728 | inline double DecimalValue<T>::ToDouble(int scale) const { |
| 729 | // Original approach was to use: |
| 730 | // static_cast<double>(value_) / pow(10.0, scale). |
| 731 | // However only integers from −2^53 to 2^53 can be represented accurately by |
| 732 | // double precision without any loss. |
| 733 | // Hence, it would not work for numbers like -0.43149576573887316. |
| 734 | // For DecimalValue representing -0.43149576573887316, value_ would be |
| 735 | // -43149576573887316 and scale would be 17. As value_ < -2^53, result would |
| 736 | // not be accurate. In newer approach we are using |
| 737 | // third party library https://github.com/lemire/fast_double_parser, |
| 738 | // which handles above scenario in a performant manner. |
| 739 | |
| 740 | bool success = false; |
| 741 | bool is_negative = false; |
| 742 | T abs_value = value_; |
| 743 | if (value_ < 0) { |
| 744 | is_negative = true; |
| 745 | // for computing absolute value cannot use std::abs |
| 746 | // as it's not supported for __int128_t |
| 747 | abs_value *= -1; |
| 748 | } |
| 749 | double result = 0; |
| 750 | // compute_float_64 only supports uint64_t currently |
| 751 | if (abs_value <= UINT64_MAX) { |
| 752 | // compute_float_64 computes value * 10^(power) whereas we want to compute |
| 753 | // value/ (10 ^ (scale)). Hence (-scale) will be passed as power to the function. |
| 754 | // It expects value to be absolute and for negative value is_negative will be set. |
| 755 | result = fast_double_parser::compute_float_64(-scale, abs_value, is_negative, |
| 756 | &success); |
| 757 | } |
| 758 | // Fallback to original approach. This is not always accurate as described above. |
| 759 | // Other alternative would be to convert value_ to string and parse it into |
| 760 | // double using std:strtod. However std::strtod is atleast 4X slower |
| 761 | // than this approach (https://github.com/lemire/fast_double_parser#sample-results) |
| 762 | // and that is excluding cost to convert value_ to string. |
| 763 | if (!success) { |
| 764 | result = static_cast<double>(value_) / pow(10.0, scale); |
| 765 | } |
| 766 | return result; |
| 767 | } |
| 768 | |
| 769 | template<typename T> |
| 770 | inline uint32_t DecimalValue<T>::Hash(int seed) const { |
no outgoing calls