|
5 | 5 | * |
6 | 6 | * 1998 Jan Wieck |
7 | 7 | * |
8 | | - * $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.39 2001/03/22 06:16:17 momjian Exp $ |
| 8 | + * $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.40 2001/04/14 02:10:57 tgl Exp $ |
9 | 9 | * |
10 | 10 | * ---------- |
11 | 11 | */ |
@@ -1134,7 +1134,6 @@ numeric_mod(PG_FUNCTION_ARGS) |
1134 | 1134 |
|
1135 | 1135 | mod_var(&arg1, &arg2, &result); |
1136 | 1136 |
|
1137 | | - result.dscale = result.rscale; |
1138 | 1137 | res = make_result(&result); |
1139 | 1138 |
|
1140 | 1139 | free_var(&result); |
@@ -3281,29 +3280,42 @@ mod_var(NumericVar *var1, NumericVar *var2, NumericVar *result) |
3281 | 3280 | { |
3282 | 3281 | NumericVar tmp; |
3283 | 3282 | int save_global_rscale; |
| 3283 | + int div_dscale; |
3284 | 3284 |
|
3285 | 3285 | init_var(&tmp); |
3286 | 3286 |
|
3287 | 3287 | /* --------- |
3288 | 3288 | * We do this using the equation |
3289 | 3289 | * mod(x,y) = x - trunc(x/y)*y |
3290 | | - * We fiddle a bit with global_rscale to control result precision. |
| 3290 | + * We set global_rscale the same way numeric_div and numeric_mul do |
| 3291 | + * to get the right answer from the equation. The final result, |
| 3292 | + * however, need not be displayed to more precision than the inputs. |
3291 | 3293 | * ---------- |
3292 | 3294 | */ |
3293 | 3295 | save_global_rscale = global_rscale; |
3294 | | - global_rscale = var2->rscale + 2; |
| 3296 | + |
| 3297 | + div_dscale = MAX(var1->dscale + var2->dscale, NUMERIC_MIN_DISPLAY_SCALE); |
| 3298 | + div_dscale = MIN(div_dscale, NUMERIC_MAX_DISPLAY_SCALE); |
| 3299 | + global_rscale = MAX(var1->rscale + var2->rscale, |
| 3300 | + NUMERIC_MIN_RESULT_SCALE); |
| 3301 | + global_rscale = MAX(global_rscale, div_dscale + 4); |
| 3302 | + global_rscale = MIN(global_rscale, NUMERIC_MAX_RESULT_SCALE); |
3295 | 3303 |
|
3296 | 3304 | div_var(var1, var2, &tmp); |
3297 | 3305 |
|
| 3306 | + tmp.dscale = div_dscale; |
| 3307 | + |
3298 | 3308 | /* do trunc() by forgetting digits to the right of the decimal point */ |
3299 | 3309 | tmp.ndigits = MAX(0, MIN(tmp.ndigits, tmp.weight + 1)); |
3300 | | - tmp.rscale = var2->rscale; |
3301 | 3310 |
|
3302 | | - global_rscale = var2->rscale; |
| 3311 | + global_rscale = var2->rscale + tmp.rscale; |
| 3312 | + |
3303 | 3313 | mul_var(var2, &tmp, &tmp); |
3304 | 3314 |
|
3305 | 3315 | sub_var(var1, &tmp, result); |
3306 | 3316 |
|
| 3317 | + result->dscale = MAX(var1->dscale, var2->dscale); |
| 3318 | + |
3307 | 3319 | global_rscale = save_global_rscale; |
3308 | 3320 | free_var(&tmp); |
3309 | 3321 | } |
|
0 commit comments