Converts an int256_t to an int128_t. int256_t does support convert_to () but that produces an approximate int128_t which makes it unusable. Instead, we'll construct it using convert_to which is exact. overflow is set to true if the value cannot be converted. The return value is undefined in this case.
| 91 | /// *overflow is set to true if the value cannot be converted. The return value is |
| 92 | /// undefined in this case. |
| 93 | inline int128_t ConvertToInt128(int256_t x, int128_t max_value, bool* overflow) { |
| 94 | bool negative = false; |
| 95 | if (x < 0) { |
| 96 | x = -x; |
| 97 | negative = true; |
| 98 | } |
| 99 | |
| 100 | /// Extract the values in base int64_t::max() and reconstruct the new value |
| 101 | /// as an int128_t. |
| 102 | uint64_t base = std::numeric_limits<int64_t>::max(); |
| 103 | int128_t result = 0; |
| 104 | int128_t scale = 1; |
| 105 | while (x != 0) { |
| 106 | uint64_t v = (x % base).convert_to<uint64_t>(); |
| 107 | x /= base; |
| 108 | *overflow |= (v > max_value / scale); |
| 109 | int128_t n = |
| 110 | ArithmeticUtil::AsUnsigned<std::multiplies>(static_cast<int128_t>(v), scale); |
| 111 | *overflow |= (result > ArithmeticUtil::AsUnsigned<std::minus>(max_value, n)); |
| 112 | result = ArithmeticUtil::AsUnsigned<std::plus>(result, n); |
| 113 | scale = |
| 114 | ArithmeticUtil::AsUnsigned<std::multiplies>(scale, static_cast<int128_t>(base)); |
| 115 | } |
| 116 | return negative ? ArithmeticUtil::Negate(result) : result; |
| 117 | } |
| 118 | |
| 119 | /// abs() is not defined for int128_t. Name it abs() so it can be compatible with |
| 120 | /// native int types in templates. |