Multiply when the out_precision is 38, and there is trimming of the scale i.e the intermediate value could be larger than the final value.
| 260 | // Multiply when the out_precision is 38, and there is trimming of the scale i.e |
| 261 | // the intermediate value could be larger than the final value. |
| 262 | static BasicDecimal128 MultiplyMaxPrecisionAndScaleDown(const BasicDecimalScalar128& x, |
| 263 | const BasicDecimalScalar128& y, |
| 264 | int32_t out_scale, |
| 265 | bool* overflow) { |
| 266 | auto delta_scale = x.scale() + y.scale() - out_scale; |
| 267 | DCHECK_GT(delta_scale, 0); |
| 268 | |
| 269 | *overflow = false; |
| 270 | BasicDecimal128 result; |
| 271 | auto x_abs = BasicDecimal128::Abs(x.value()); |
| 272 | auto y_abs = BasicDecimal128::Abs(y.value()); |
| 273 | |
| 274 | // It's possible that the intermediate value does not fit in 128-bits, but the |
| 275 | // final value will (after scaling down). |
| 276 | bool needs_int256 = false; |
| 277 | int32_t total_leading_zeros = |
| 278 | x_abs.CountLeadingBinaryZeros() + y_abs.CountLeadingBinaryZeros(); |
| 279 | // This check is quick, but conservative. In some cases it will indicate that |
| 280 | // converting to 256 bits is necessary, when it's not actually the case. |
| 281 | needs_int256 = total_leading_zeros <= 128; |
| 282 | if (ARROW_PREDICT_FALSE(needs_int256)) { |
| 283 | int64_t result_high; |
| 284 | uint64_t result_low; |
| 285 | |
| 286 | // This requires converting to 256-bit, and we use the boost library for that. To |
| 287 | // avoid references to boost from the precompiled-to-ir code (this causes issues |
| 288 | // with symbol resolution at runtime), we use a wrapper exported from the CPP code. |
| 289 | gdv_xlarge_multiply_and_scale_down(x.value().high_bits(), x.value().low_bits(), |
| 290 | y.value().high_bits(), y.value().low_bits(), |
| 291 | delta_scale, &result_high, &result_low, overflow); |
| 292 | result = BasicDecimal128(result_high, result_low); |
| 293 | } else { |
| 294 | if (ARROW_PREDICT_TRUE(delta_scale <= 38)) { |
| 295 | // The largest value that result can have here is (2^64 - 1) * (2^63 - 1), which is |
| 296 | // greater than BasicDecimal128::kMaxValue. |
| 297 | result = x.value() * y.value(); |
| 298 | // Since delta_scale is greater than zero, result can now be at most |
| 299 | // ((2^64 - 1) * (2^63 - 1)) / 10, which is less than BasicDecimal128::kMaxValue, so |
| 300 | // there cannot be any overflow. |
| 301 | result = result.ReduceScaleBy(delta_scale); |
| 302 | } else { |
| 303 | // We are multiplying decimal(38, 38) by decimal(38, 38). The result should be a |
| 304 | // decimal(38, 37), so delta scale = 38 + 38 - 37 = 39. Since we are not in the |
| 305 | // 256 bit intermediate value case and we are scaling down by 39, then we are |
| 306 | // guaranteed that the result is 0 (even if we try to round). The largest possible |
| 307 | // intermediate result is 38 "9"s. If we scale down by 39, the leftmost 9 is now |
| 308 | // two digits to the right of the rightmost "visible" one. The reason why we have |
| 309 | // to handle this case separately is because a scale multiplier with a delta_scale |
| 310 | // 39 does not fit into 128 bit. |
| 311 | DCHECK_EQ(delta_scale, 39); |
| 312 | result = 0; |
| 313 | } |
| 314 | } |
| 315 | return result; |
| 316 | } |
| 317 | |
| 318 | // Multiply when the out_precision is 38. |
| 319 | static BasicDecimal128 MultiplyMaxPrecision(const BasicDecimalScalar128& x, |
no test coverage detected