aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/numeric.c
diff options
context:
space:
mode:
authorDean Rasheed <dean.a.rasheed@gmail.com>2023-02-02 09:41:22 +0000
committerDean Rasheed <dean.a.rasheed@gmail.com>2023-02-02 09:41:22 +0000
commit0736fc1ceb0659a9f73699910ac56603336daeee (patch)
treeb303d350d99bc9a66fad349f7ce2ea109d8e8beb /src/backend/utils/adt/numeric.c
parent9a84f2947bf9345ad6b93ba37da63633649eaea8 (diff)
downloadpostgresql-0736fc1ceb0659a9f73699910ac56603336daeee.tar.gz
postgresql-0736fc1ceb0659a9f73699910ac56603336daeee.zip
Clarify the choice of rscale in numeric_sqrt().
Improve the comment explaining the choice of rscale in numeric_sqrt(), and ensure that the code works consistently when other values of NBASE/DEC_DIGITS are used. Note that, in practice, we always expect DEC_DIGITS == 4, and this does not change the computation in that case. Joel Jacobson and Dean Rasheed Discussion: https://postgr.es/m/06712c29-98e9-43b3-98da-f234d81c6e49%40app.fastmail.com
Diffstat (limited to 'src/backend/utils/adt/numeric.c')
-rw-r--r--src/backend/utils/adt/numeric.c17
1 files changed, 15 insertions, 2 deletions
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 834339dcff2..08c841675d8 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -3693,8 +3693,21 @@ numeric_sqrt(PG_FUNCTION_ARGS)
init_var(&result);
- /* Assume the input was normalized, so arg.weight is accurate */
- sweight = (arg.weight + 1) * DEC_DIGITS / 2 - 1;
+ /*
+ * Assume the input was normalized, so arg.weight is accurate. The result
+ * then has at least sweight = floor(arg.weight * DEC_DIGITS / 2 + 1)
+ * digits before the decimal point. When DEC_DIGITS is even, we can save
+ * a few cycles, since the division is exact and there is no need to round
+ * towards negative infinity.
+ */
+#if DEC_DIGITS == ((DEC_DIGITS / 2) * 2)
+ sweight = arg.weight * DEC_DIGITS / 2 + 1;
+#else
+ if (arg.weight >= 0)
+ sweight = arg.weight * DEC_DIGITS / 2 + 1;
+ else
+ sweight = 1 - (1 - arg.weight * DEC_DIGITS) / 2;
+#endif
rscale = NUMERIC_MIN_SIG_DIGITS - sweight;
rscale = Max(rscale, arg.dscale);