cpp/src/gandiva/precompiled/decimal_ops.cc
// 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.
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.
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 .
static BasicDecimal128 MultiplyMaxPrecisionAndScaleDown(const BasicDecimalScalar128& x,
                                                        const BasicDecimalScalar128& y,
                                                        int32_t out_scale,
                                                        bool* overflow) {
  auto delta_scale = x.scale() + y.scale() - out_scale;
  DCHECK_GT(delta_scale, 0);
  *overflow = false;
  BasicDecimal128 result;
  auto x_abs = BasicDecimal128::Abs(x.value());
  auto y_abs = BasicDecimal128::Abs(y.value());
  bool needs_int256 = false;
  int32_t total_leading_zeros =
      x_abs.CountLeadingBinaryZeros() + y_abs.CountLeadingBinaryZeros();
  needs_int256 = total_leading_zeros <= 128;
  if (ARROW_PREDICT_FALSE(needs_int256)) {
    int64_t result_high;
    uint64_t result_low;
    gdv_xlarge_multiply_and_scale_down(x.value().high_bits(), x.value().low_bits(),
                                       y.value().high_bits(), y.value().low_bits(),
                                       delta_scale, &result_high, &result_low, overflow);
    result = BasicDecimal128(result_high, result_low);
  } else {
    if (ARROW_PREDICT_TRUE(delta_scale <= 38)) {
      result = x.value() * y.value();
      result = result.ReduceScaleBy(delta_scale);
    } else {
      DCHECK_EQ(delta_scale, 39);
      result = 0;
    }
  }
  return result;
}
static BasicDecimal128 MultiplyMaxPrecisionAndScaleDown ( const BasicDecimalScalar128 & x , const BasicDecimalScalar128 & y , int32_t out_scale , bool * overflow ) { auto delta_scale = x . scale ( ) + y . scale ( ) - out_scale ; DCHECK_GT ( delta_scale , 0 ) ; * overflow = false ; BasicDecimal128 result ; auto x_abs = BasicDecimal128 :: Abs ( x . value ( ) ) ; auto y_abs = BasicDecimal128 :: Abs ( y . value ( ) ) ; bool needs_int256 = false ; int32_t total_leading_zeros = x_abs . CountLeadingBinaryZeros ( ) + y_abs . CountLeadingBinaryZeros ( ) ; needs_int256 = total_leading_zeros <= 128 ; if ( ARROW_PREDICT_FALSE ( needs_int256 ) ) { int64_t result_high ; uint64_t result_low ; gdv_xlarge_multiply_and_scale_down ( x . value ( ) . high_bits ( ) , x . value ( ) . low_bits ( ) , y . value ( ) . high_bits ( ) , y . value ( ) . low_bits ( ) , delta_scale , & result_high , & result_low , overflow ) ; result = BasicDecimal128 ( result_high , result_low ) ; } else { if ( ARROW_PREDICT_TRUE ( delta_scale <= 38 ) ) { result = x . value ( ) * y . value ( ) ; result = result . ReduceScaleBy ( delta_scale ) ; } else { DCHECK_EQ ( delta_scale , 39 ) ; result = 0 ; } } return result ; }
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.
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 .
// It's possible that the intermediate value does not fit in 128-bits, but the // final value will (after scaling down). // This check is quick, but conservative. In some cases it will indicate that // converting to 256 bits is necessary, when it's not actually the case. // This requires converting to 256-bit, and we use the boost library for that. To // avoid references to boost from the precompiled-to-ir code (this causes issues // with symbol resolution at runtime), we use a wrapper exported from the CPP code. // The largest value that result can have here is (2^64 - 1) * (2^63 - 1), which is // greater than BasicDecimal128::kMaxValue. // Since delta_scale is greater than zero, result can now be at most // ((2^64 - 1) * (2^63 - 1)) / 10, which is less than BasicDecimal128::kMaxValue, so // there cannot be any overflow. // We are multiplying decimal(38, 38) by decimal(38, 38). The result should be a // decimal(38, 37), so delta scale = 38 + 38 - 37 = 39. Since we are not in the // 256 bit intermediate value case and we are scaling down by 39, then we are // guaranteed that the result is 0 (even if we try to round). The largest possible // intermediate result is 38 "9"s. If we scale down by 39, the leftmost 9 is now // two digits to the right of the rightmost "visible" one. The reason why we have // to handle this case separately is because a scale multiplier with a delta_scale // 39 does not fit into 128 bit.