From f578051209ec952873795beabadd40b54dbf182a Mon Sep 17 00:00:00 2001
From: Dean Rasheed <dean.a.rasheed@gmail.com>
Date: Sun, 20 Feb 2022 18:10:25 +0000
Subject: [PATCH 3/3] Use div_var() instead of div_var_fast() when the divisor
 is small.

When the divisor contains just one base-NBASE digit, div_var() is much
faster than div_var_fast(), since it contains special fast-path code
for that case, and when the divisor has two digits, div_var() is still
somewhat faster, since div_var_fast() has more overhead intended for
larger inputs. Therefore, use div_var() instead of div_var_fast() in
such cases.

Where we know for sure that the divisor is small, such as the
denominators of Taylor series terms, just call div_var() directly.
Otherwise, have div_var_fast() delegate to div_var() when the
divisor is small. This produces a noticeable speedup of exp(), ln()
and the numeric-big regression test.
---
 src/backend/utils/adt/numeric.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 909f4eed74..3c1e310ce2 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -8725,6 +8725,16 @@ div_var_fast(const NumericVar *var1, const NumericVar *var2,
 	NumericDigit *var1digits = var1->digits;
 	NumericDigit *var2digits = var2->digits;
 
+	/*
+	 * If the divisor has just one or two base-NBASE digits, it is
+	 * significantly faster to just use div_var().
+	 */
+	if (var2ndigits <= 2)
+	{
+		div_var(var1, var2, result, rscale, round);
+		return;
+	}
+
 	/*
 	 * First of all division by zero check; we must not be handed an
 	 * unnormalized divisor.
@@ -9840,7 +9850,7 @@ exp_var(const NumericVar *arg, NumericVar *result, int rscale)
 		}
 
 		local_rscale = x.dscale + ndiv2;
-		div_var_fast(&x, &tmp, &x, local_rscale, true);
+		div_var(&x, &tmp, &x, local_rscale, true);
 
 		free_var(&tmp);
 	}
@@ -9871,7 +9881,7 @@ exp_var(const NumericVar *arg, NumericVar *result, int rscale)
 
 	mul_var(&x, &x, &elem, local_rscale);
 	set_var_from_var(&const_two, &ni);
-	div_var_fast(&elem, &ni, &elem, local_rscale, true);
+	div_var(&elem, &ni, &elem, local_rscale, true);
 
 	while (elem.ndigits != 0)
 	{
@@ -9879,7 +9889,7 @@ exp_var(const NumericVar *arg, NumericVar *result, int rscale)
 
 		mul_var(&elem, &x, &elem, local_rscale);
 		add_var(&ni, &const_one, &ni);
-		div_var_fast(&elem, &ni, &elem, local_rscale, true);
+		div_var(&elem, &ni, &elem, local_rscale, true);
 	}
 
 	/*
@@ -10079,7 +10089,7 @@ ln_var(const NumericVar *arg, NumericVar *result, int rscale)
 	{
 		add_var(&ni, &const_two, &ni);
 		mul_var(&xx, &x, &xx, local_rscale);
-		div_var_fast(&xx, &ni, &elem, local_rscale, true);
+		div_var(&xx, &ni, &elem, local_rscale, true);
 
 		if (elem.ndigits == 0)
 			break;
-- 
2.26.2

