MCPcopy Create free account
hub / github.com/apache/arrow / MultiplyMaxPrecisionAndScaleDown

Function MultiplyMaxPrecisionAndScaleDown

cpp/src/gandiva/precompiled/decimal_ops.cc:262–316  ·  view source on GitHub ↗

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.

Source from the content-addressed store, hash-verified

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.
262static 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.
319static BasicDecimal128 MultiplyMaxPrecision(const BasicDecimalScalar128& x,

Callers 1

MultiplyMaxPrecisionFunction · 0.85

Calls 7

BasicDecimal128Function · 0.85
ReduceScaleByMethod · 0.80
AbsFunction · 0.50
scaleMethod · 0.45
valueMethod · 0.45

Tested by

no test coverage detected