From 070bca416c0a78f4ce32a25c1225e820c820498a Mon Sep 17 00:00:00 2001 From: Joel Jakobsson Date: Mon, 1 Jul 2024 07:44:46 +0200 Subject: [PATCH] Optimize numeric multiplication for up to two base-NBASE digit operands --- src/backend/utils/adt/numeric.c | 52 +++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index 5510a203b0..d6c9017a35 100644 --- a/src/backend/utils/adt/numeric.c +++ b/src/backend/utils/adt/numeric.c @@ -8747,6 +8747,58 @@ mul_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result, return; } + /* + * If var1 and var2 are just one or two digits, their product will fit in + * an int64 can be computed directly, which is significantly faster. + */ + if (var2ndigits <= 2) + { + int64 product; + + switch (var1ndigits) + { + case 1: + product = var1digits[0]; + break; + case 2: + product = var1digits[0] * NBASE + var1digits[1]; + break; + } + + switch (var2ndigits) + { + case 1: + product *= var2digits[0]; + break; + case 2: + product *= var2digits[0] * NBASE + var2digits[1]; + break; + } + + alloc_var(result, res_ndigits); + res_digits = result->digits; + for (i = res_ndigits - 1; i >= 0; i--) + { + res_digits[i] = product % NBASE; + product /= NBASE; + } + Assert(product == 0); + + /* + * Finally, round the result to the requested precision. + */ + result->weight = res_weight; + result->sign = res_sign; + + /* Round to target rscale (and set result->dscale) */ + round_var(result, rscale); + + /* Strip leading and trailing zeroes */ + strip_var(result); + + return; + } + /* * We do the arithmetic in an array "dig[]" of signed int's. Since * INT_MAX is noticeably larger than NBASE*NBASE, this gives us headroom -- 2.45.1