Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit18a02ad

Browse files
committed
Fix corner-case loss of precision in numeric pow() calculation
Commit7d9a473 greatly improved theaccuracy of the numeric transcendental functions, however it failed toconsider the case where the result from pow() is close to the overflowthreshold, for example 0.12 ^ -2345.6. For such inputs, where theresult has more than 2000 digits before the decimal point, the decimalresult weight estimate was being clamped to 2000, leading to a loss ofprecision in the final calculation.Fix this by replacing the clamping code with an overflow test thataborts the calculation early if the final result is sure to overflow,based on the overflow limit in exp_var(). This provides the sameprotection against integer overflow in the subsequent result scalecomputation as the original clamping code, but it also ensures thatprecision is never lost and saves compute cycles in cases that aresure to overflow.The new early overflow test works with the initial low-precisionresult (expected to be accurate to around 8 significant digits) andincludes a small fuzz factor to ensure that it doesn't kick in forvalues that would not overflow exp_var(), so the overall overflowthreshold of pow() is unchanged and consistent for all inputs withnon-integer exponents.Author: Dean RasheedReviewed-by: Tom LaneDiscussion:http://www.postgresql.org/message-id/CAEZATCUj3U-cQj0jjoia=qgs0SjE3auroxh8swvNKvZWUqegrg@mail.gmail.comSee-also:http://www.postgresql.org/message-id/CAEZATCV7w+8iB=07dJ8Q0zihXQT1semcQuTeK+4_rogC_zq5Hw@mail.gmail.com
1 parentc1543a8 commit18a02ad

File tree

3 files changed

+40
-4
lines changed

3 files changed

+40
-4
lines changed

‎src/backend/utils/adt/numeric.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7591,6 +7591,7 @@ exp_var(NumericVar *arg, NumericVar *result, int rscale)
75917591
val=numericvar_to_double_no_overflow(&x);
75927592

75937593
/* Guard against overflow */
7594+
/* If you change this limit, see also power_var()'s limit */
75947595
if (Abs(val) >=NUMERIC_MAX_RESULT_SCALE*3)
75957596
ereport(ERROR,
75967597
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
@@ -7992,6 +7993,15 @@ power_var(NumericVar *base, NumericVar *exp, NumericVar *result)
79927993
*
79937994
* We want result = e ^ (exp * ln(base))
79947995
* so result dweight = log10(result) = exp * ln(base) * log10(e)
7996+
*
7997+
* We also perform a crude overflow test here so that we can exit early if
7998+
* the full-precision result is sure to overflow, and to guard against
7999+
* integer overflow when determining the scale for the real calculation.
8000+
* exp_var() supports inputs up to NUMERIC_MAX_RESULT_SCALE * 3, so the
8001+
* result will overflow if exp * ln(base) >= NUMERIC_MAX_RESULT_SCALE * 3.
8002+
* Since the values here are only approximations, we apply a small fuzz
8003+
* factor to this overflow test and let exp_var() determine the exact
8004+
* overflow threshold so that it is consistent for all inputs.
79958005
*----------
79968006
*/
79978007
ln_dweight=estimate_ln_dweight(base);
@@ -8006,11 +8016,13 @@ power_var(NumericVar *base, NumericVar *exp, NumericVar *result)
80068016

80078017
val=numericvar_to_double_no_overflow(&ln_num);
80088018

8009-
val *=0.434294481903252;/* approximate decimal result weight */
8019+
/* initial overflow test with fuzz factor */
8020+
if (Abs(val)>NUMERIC_MAX_RESULT_SCALE*3.01)
8021+
ereport(ERROR,
8022+
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
8023+
errmsg("value overflows numeric format")));
80108024

8011-
/* limit to something that won't cause integer overflow */
8012-
val=Max(val,-NUMERIC_MAX_RESULT_SCALE);
8013-
val=Min(val,NUMERIC_MAX_RESULT_SCALE);
8025+
val *=0.434294481903252;/* approximate decimal result weight */
80148026

80158027
/* choose the result scale */
80168028
rscale=NUMERIC_MIN_SIG_DIGITS- (int)val;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp