diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index a83feea396..dea55847fd 100644 --- a/src/backend/utils/adt/numeric.c +++ b/src/backend/utils/adt/numeric.c @@ -301,6 +301,7 @@ struct NumericData * This is feasible because the digit buffer is separate from the variable. * ---------- */ +#define FIXED_BUF_LEN 8 typedef struct NumericVar { int ndigits; /* # of digits in digits[] - can be 0! */ @@ -309,6 +310,8 @@ typedef struct NumericVar int dscale; /* display scale */ NumericDigit *buf; /* start of palloc'd space for digits[] */ NumericDigit *digits; /* base-NBASE digits */ + int buf_len; + NumericDigit fixed_buf[FIXED_BUF_LEN]; } NumericVar; @@ -321,6 +324,7 @@ typedef struct NumericVar current; NumericVar stop; NumericVar step; + NumericVar tmp_var; } generate_series_numeric_fctx; @@ -414,18 +418,18 @@ typedef struct NumericSumAccum */ static const NumericDigit const_zero_data[1] = {0}; static const NumericVar const_zero = -{0, 0, NUMERIC_POS, 0, NULL, (NumericDigit *) const_zero_data}; +{0, 0, NUMERIC_POS, 0, NULL, (NumericDigit *) const_zero_data, 0, {0}}; static const NumericDigit const_one_data[1] = {1}; static const NumericVar const_one = -{1, 0, NUMERIC_POS, 0, NULL, (NumericDigit *) const_one_data}; +{1, 0, NUMERIC_POS, 0, NULL, (NumericDigit *) const_one_data, 0, {0}}; static const NumericVar const_minus_one = -{1, 0, NUMERIC_NEG, 0, NULL, (NumericDigit *) const_one_data}; +{1, 0, NUMERIC_NEG, 0, NULL, (NumericDigit *) const_one_data, 0, {0}}; static const NumericDigit const_two_data[1] = {2}; static const NumericVar const_two = -{1, 0, NUMERIC_POS, 0, NULL, (NumericDigit *) const_two_data}; +{1, 0, NUMERIC_POS, 0, NULL, (NumericDigit *) const_two_data, 0, {0}}; #if DEC_DIGITS == 4 static const NumericDigit const_zero_point_nine_data[1] = {9000}; @@ -435,7 +439,7 @@ static const NumericDigit const_zero_point_nine_data[1] = {90}; static const NumericDigit const_zero_point_nine_data[1] = {9}; #endif static const NumericVar const_zero_point_nine = -{1, -1, NUMERIC_POS, 1, NULL, (NumericDigit *) const_zero_point_nine_data}; +{1, -1, NUMERIC_POS, 1, NULL, (NumericDigit *) const_zero_point_nine_data, 0, {0}}; #if DEC_DIGITS == 4 static const NumericDigit const_one_point_one_data[2] = {1, 1000}; @@ -445,16 +449,16 @@ static const NumericDigit const_one_point_one_data[2] = {1, 10}; static const NumericDigit const_one_point_one_data[2] = {1, 1}; #endif static const NumericVar const_one_point_one = -{2, 0, NUMERIC_POS, 1, NULL, (NumericDigit *) const_one_point_one_data}; +{2, 0, NUMERIC_POS, 1, NULL, (NumericDigit *) const_one_point_one_data, 0, {0}}; static const NumericVar const_nan = -{0, 0, NUMERIC_NAN, 0, NULL, NULL}; +{0, 0, NUMERIC_NAN, 0, NULL, NULL, 0, {0}}; static const NumericVar const_pinf = -{0, 0, NUMERIC_PINF, 0, NULL, NULL}; +{0, 0, NUMERIC_PINF, 0, NULL, NULL, 0, {0}}; static const NumericVar const_ninf = -{0, 0, NUMERIC_NINF, 0, NULL, NULL}; +{0, 0, NUMERIC_NINF, 0, NULL, NULL, 0, {0}}; #if DEC_DIGITS == 4 static const int round_powers[4] = {0, 1000, 100, 10}; @@ -1770,6 +1774,7 @@ generate_series_step_numeric(PG_FUNCTION_ARGS) init_var(&fctx->current); init_var(&fctx->stop); init_var(&fctx->step); + init_var(&fctx->tmp_var); set_var_from_num(start_num, &fctx->current); set_var_from_num(stop_num, &fctx->stop); @@ -1799,7 +1804,8 @@ generate_series_step_numeric(PG_FUNCTION_ARGS) oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /* increment current in preparation for next iteration */ - add_var(&fctx->current, &fctx->step, &fctx->current); + set_var_from_var(&fctx->current, &fctx->tmp_var); + add_var(&fctx->tmp_var, &fctx->step, &fctx->current); MemoryContextSwitchTo(oldcontext); /* do when there is more left to send */ @@ -1917,35 +1923,42 @@ compute_bucket(Numeric operand, Numeric bound1, Numeric bound2, const NumericVar *count_var, bool reversed_bounds, NumericVar *result_var) { - NumericVar bound1_var; - NumericVar bound2_var; - NumericVar operand_var; + NumericVar tmp_var1; + NumericVar tmp_var2; + NumericVar tmp_var3; + NumericVar tmp_var4; - init_var_from_num(bound1, &bound1_var); - init_var_from_num(bound2, &bound2_var); - init_var_from_num(operand, &operand_var); + init_var_from_num(bound1, &tmp_var1); + init_var_from_num(bound2, &tmp_var2); + init_var_from_num(operand, &tmp_var3); + init_var(&tmp_var4); if (!reversed_bounds) { - sub_var(&operand_var, &bound1_var, &operand_var); - sub_var(&bound2_var, &bound1_var, &bound2_var); + set_var_from_var(&tmp_var3, &tmp_var4); + sub_var(&tmp_var4, &tmp_var1, &tmp_var3); + set_var_from_var(&tmp_var2, &tmp_var4); + sub_var(&tmp_var4, &tmp_var1, &tmp_var2); } else { - sub_var(&bound1_var, &operand_var, &operand_var); - sub_var(&bound1_var, &bound2_var, &bound2_var); + set_var_from_var(&tmp_var3, &tmp_var4); + sub_var(&tmp_var1, &tmp_var4, &tmp_var3); + set_var_from_var(&tmp_var2, &tmp_var4); + sub_var(&tmp_var1, &tmp_var4, &tmp_var2); } - mul_var(&operand_var, count_var, &operand_var, - operand_var.dscale + count_var->dscale); - div_var(&operand_var, &bound2_var, result_var, - select_div_scale(&operand_var, &bound2_var), true); - add_var(result_var, &const_one, result_var); + mul_var(&tmp_var3, count_var, &tmp_var3, + tmp_var3.dscale + count_var->dscale); + div_var(&tmp_var3, &tmp_var2, &tmp_var4, + select_div_scale(&tmp_var3, &tmp_var2), true); + add_var(&tmp_var4, &const_one, result_var); floor_var(result_var, result_var); - free_var(&bound1_var); - free_var(&bound2_var); - free_var(&operand_var); + free_var(&tmp_var1); + free_var(&tmp_var2); + free_var(&tmp_var3); + free_var(&tmp_var4); } /* ---------------------------------------------------------------------- @@ -3426,8 +3439,11 @@ numeric_inc(PG_FUNCTION_ARGS) { Numeric num = PG_GETARG_NUMERIC(0); NumericVar arg; + NumericVar result; Numeric res; + init_var(&result); + /* * Handle NaN and infinities */ @@ -3439,11 +3455,11 @@ numeric_inc(PG_FUNCTION_ARGS) */ init_var_from_num(num, &arg); - add_var(&arg, &const_one, &arg); + add_var(&arg, &const_one, &result); - res = make_result(&arg); + res = make_result(&result); - free_var(&arg); + free_var(&result); PG_RETURN_NUMERIC(res); } @@ -3555,7 +3571,8 @@ numeric_lcm(PG_FUNCTION_ARGS) Numeric num2 = PG_GETARG_NUMERIC(1); NumericVar arg1; NumericVar arg2; - NumericVar result; + NumericVar tmp_var1; + NumericVar tmp_var2; Numeric res; /* @@ -3571,7 +3588,8 @@ numeric_lcm(PG_FUNCTION_ARGS) init_var_from_num(num1, &arg1); init_var_from_num(num2, &arg2); - init_var(&result); + init_var(&tmp_var1); + init_var(&tmp_var2); /* * Compute the result using lcm(x, y) = abs(x / gcd(x, y) * y), returning @@ -3584,20 +3602,21 @@ numeric_lcm(PG_FUNCTION_ARGS) * display scale is no smaller than either input. */ if (arg1.ndigits == 0 || arg2.ndigits == 0) - set_var_from_var(&const_zero, &result); + set_var_from_var(&const_zero, &tmp_var1); else { - gcd_var(&arg1, &arg2, &result); - div_var(&arg1, &result, &result, 0, false); - mul_var(&arg2, &result, &result, arg2.dscale); - result.sign = NUMERIC_POS; + gcd_var(&arg1, &arg2, &tmp_var1); + div_var(&arg1, &tmp_var1, &tmp_var2, 0, false); + mul_var(&arg2, &tmp_var2, &tmp_var1, arg2.dscale); + tmp_var1.sign = NUMERIC_POS; } - result.dscale = Max(arg1.dscale, arg2.dscale); + tmp_var1.dscale = Max(arg1.dscale, arg2.dscale); - res = make_result(&result); + res = make_result(&tmp_var1); - free_var(&result); + free_var(&tmp_var1); + free_var(&tmp_var2); PG_RETURN_NUMERIC(res); } @@ -6130,7 +6149,8 @@ numeric_stddev_internal(NumericAggState *state, NumericVar vN, vsumX, vsumX2, - vNminus1; + vNminus1, + tmpVar; int64 totCount; int rscale; @@ -6164,6 +6184,7 @@ numeric_stddev_internal(NumericAggState *state, init_var(&vN); init_var(&vsumX); init_var(&vsumX2); + init_var(&tmpVar); int64_to_numericvar(state->N, &vN); accum_sum_final(&(state->sumX), &vsumX); @@ -6177,7 +6198,9 @@ numeric_stddev_internal(NumericAggState *state, mul_var(&vsumX, &vsumX, &vsumX, rscale); /* vsumX = sumX * sumX */ mul_var(&vN, &vsumX2, &vsumX2, rscale); /* vsumX2 = N * sumX2 */ - sub_var(&vsumX2, &vsumX, &vsumX2); /* N * sumX2 - sumX * sumX */ + + set_var_from_var(&vsumX2, &tmpVar); + sub_var(&tmpVar, &vsumX, &vsumX2); /* N * sumX2 - sumX * sumX */ if (cmp_var(&vsumX2, &const_zero) <= 0) { @@ -6871,11 +6894,35 @@ dump_var(const char *str, NumericVar *var) static void alloc_var(NumericVar *var, int ndigits) { - digitbuf_free(var->buf); - var->buf = digitbuf_alloc(ndigits + 1); - var->buf[0] = 0; /* spare digit for rounding */ - var->digits = var->buf + 1; - var->ndigits = ndigits; + if (ndigits <= FIXED_BUF_LEN - 1) + { + if (var->buf_len > 0) + { + digitbuf_free(var->buf); + var->buf_len = 0; + } + var->fixed_buf[0] = 0; /* spare digit for rounding */ + var->digits = var->fixed_buf + 1; + var->ndigits = ndigits; + } + else if (ndigits < var->buf_len) + { + var->buf[0] = 0; + var->digits = var->buf + 1; + var->ndigits = ndigits; + } + else + { + if (var->buf_len > 0) + { + digitbuf_free(var->buf); + } + var->buf = digitbuf_alloc(ndigits + 1); + var->buf_len = ndigits + 1; + var->buf[0] = 0; /* spare digit for rounding */ + var->digits = var->buf + 1; + var->ndigits = ndigits; + } } @@ -6887,8 +6934,12 @@ alloc_var(NumericVar *var, int ndigits) static void free_var(NumericVar *var) { - digitbuf_free(var->buf); - var->buf = NULL; + if (var->buf_len > 0) + { + digitbuf_free(var->buf); + var->buf = NULL; + var->buf_len = 0; + } var->digits = NULL; var->sign = NUMERIC_NAN; } @@ -6903,8 +6954,12 @@ free_var(NumericVar *var) static void zero_var(NumericVar *var) { - digitbuf_free(var->buf); - var->buf = NULL; + if (var->buf_len > 0) + { + digitbuf_free(var->buf); + var->buf = NULL; + var->buf_len = 0; + } var->digits = NULL; var->ndigits = 0; var->weight = 0; /* by convention; doesn't really matter */ @@ -7166,8 +7221,10 @@ set_var_from_non_decimal_integer_str(const char *str, const char *cp, int sign, int64 tmp; int64 mul; NumericVar tmp_var; + NumericVar tmp_var2; init_var(&tmp_var); + init_var(&tmp_var2); zero_var(dest); @@ -7190,9 +7247,9 @@ set_var_from_non_decimal_integer_str(const char *str, const char *cp, int sign, { /* Add the contribution from this group of digits */ int64_to_numericvar(mul, &tmp_var); - mul_var(dest, &tmp_var, dest, 0); + mul_var(dest, &tmp_var, &tmp_var2, 0); int64_to_numericvar(tmp, &tmp_var); - add_var(dest, &tmp_var, dest); + add_var(&tmp_var2, &tmp_var, dest); /* Result will overflow if weight overflows int16 */ if (dest->weight > SHRT_MAX) @@ -7227,9 +7284,9 @@ set_var_from_non_decimal_integer_str(const char *str, const char *cp, int sign, { /* Add the contribution from this group of digits */ int64_to_numericvar(mul, &tmp_var); - mul_var(dest, &tmp_var, dest, 0); + mul_var(dest, &tmp_var, &tmp_var2, 0); int64_to_numericvar(tmp, &tmp_var); - add_var(dest, &tmp_var, dest); + add_var(&tmp_var2, &tmp_var, dest); /* Result will overflow if weight overflows int16 */ if (dest->weight > SHRT_MAX) @@ -7264,9 +7321,9 @@ set_var_from_non_decimal_integer_str(const char *str, const char *cp, int sign, { /* Add the contribution from this group of digits */ int64_to_numericvar(mul, &tmp_var); - mul_var(dest, &tmp_var, dest, 0); + mul_var(dest, &tmp_var, &tmp_var2, 0); int64_to_numericvar(tmp, &tmp_var); - add_var(dest, &tmp_var, dest); + add_var(&tmp_var2, &tmp_var, dest); /* Result will overflow if weight overflows int16 */ if (dest->weight > SHRT_MAX) @@ -7301,9 +7358,9 @@ set_var_from_non_decimal_integer_str(const char *str, const char *cp, int sign, /* Add the contribution from the final group of digits */ int64_to_numericvar(mul, &tmp_var); - mul_var(dest, &tmp_var, dest, 0); + mul_var(dest, &tmp_var, &tmp_var2, 0); int64_to_numericvar(tmp, &tmp_var); - add_var(dest, &tmp_var, dest); + add_var(&tmp_var2, &tmp_var, dest); if (dest->weight > SHRT_MAX) goto out_of_range; @@ -7375,6 +7432,7 @@ init_var_from_num(Numeric num, NumericVar *dest) dest->dscale = NUMERIC_DSCALE(num); dest->digits = NUMERIC_DIGITS(num); dest->buf = NULL; /* digits array is not palloc'd */ + dest->buf_len = 0; } @@ -7388,17 +7446,54 @@ set_var_from_var(const NumericVar *value, NumericVar *dest) { NumericDigit *newbuf; - newbuf = digitbuf_alloc(value->ndigits + 1); - newbuf[0] = 0; /* spare digit for rounding */ - if (value->ndigits > 0) /* else value->digits might be null */ - memcpy(newbuf + 1, value->digits, - value->ndigits * sizeof(NumericDigit)); + if (value->ndigits <= FIXED_BUF_LEN - 1) + { + if (unlikely(dest->buf_len > 0)) + { + digitbuf_free(dest->buf); + } + memmove(dest, value, sizeof(NumericVar)); + dest->buf = NULL; + dest->buf_len = 0; + newbuf = dest->fixed_buf; + newbuf[0] = 0; /* spare digit for rounding */ + if (value->ndigits > 0) /* else value->digits might be null */ + memcpy(newbuf + 1, value->digits, + value->ndigits * sizeof(NumericDigit)); + dest->digits = newbuf + 1; + } + else if (value->ndigits <= dest->buf_len - 1) + { + int buf_len = dest->buf_len; + newbuf = dest->buf; + newbuf[0] = 0; /* spare digit for rounding */ + memmove(dest, value, sizeof(NumericVar)); + if (value->ndigits > 0) /* else value->digits might be null */ + memmove(newbuf + 1, value->digits, + value->ndigits * sizeof(NumericDigit)); + dest->buf = newbuf; + dest->digits = newbuf + 1; + dest->buf_len = buf_len; - digitbuf_free(dest->buf); + } + else + { + newbuf = digitbuf_alloc(value->ndigits + 1); + newbuf[0] = 0; /* spare digit for rounding */ + if (value->ndigits > 0) /* else value->digits might be null */ + memcpy(newbuf + 1, value->digits, + value->ndigits * sizeof(NumericDigit)); - memmove(dest, value, sizeof(NumericVar)); - dest->buf = newbuf; - dest->digits = newbuf + 1; + if (dest->buf_len > 0) + { + digitbuf_free(dest->buf); + } + + memmove(dest, value, sizeof(NumericVar)); + dest->buf = newbuf; + dest->buf_len = value->ndigits + 1; + dest->digits = newbuf + 1; + } } @@ -7567,6 +7662,7 @@ get_str_from_var_sci(const NumericVar *var, int rscale) { int32 exponent; NumericVar tmp_var; + NumericVar tmp_var2; size_t len; char *str; char *sig_out; @@ -7607,9 +7703,11 @@ get_str_from_var_sci(const NumericVar *var, int rscale) * decimal digits in the process. */ init_var(&tmp_var); + init_var(&tmp_var2); power_ten_int(exponent, &tmp_var); - div_var(var, &tmp_var, &tmp_var, rscale, true); + set_var_from_var(&tmp_var, &tmp_var2); + div_var(var, &tmp_var2, &tmp_var, rscale, true); sig_out = get_str_from_var(&tmp_var); free_var(&tmp_var); @@ -8814,6 +8912,9 @@ div_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result, int var1ndigits = var1->ndigits; int var2ndigits = var2->ndigits; + Assert(var1 != result); + Assert(var2 != result); + /* * First of all division by zero check; we must not be handed an * unnormalized divisor. @@ -9127,6 +9228,9 @@ div_var_fast(const NumericVar *var1, const NumericVar *var2, NumericDigit *var1digits = var1->digits; NumericDigit *var2digits = var2->digits; + Assert(var1 != result); + Assert(var2 != result); + /* * First of all division by zero check; we must not be handed an * unnormalized divisor. @@ -9473,11 +9577,12 @@ div_var_int(const NumericVar *var, int ival, int ival_weight, int res_sign; int res_weight; int res_ndigits; - NumericDigit *res_buf; NumericDigit *res_digits; uint32 divisor; int i; + Assert (var != result); + /* Guard against division by zero */ if (ival == 0) ereport(ERROR, @@ -9510,9 +9615,8 @@ div_var_int(const NumericVar *var, int ival, int ival_weight, if (round) res_ndigits++; - res_buf = digitbuf_alloc(res_ndigits + 1); - res_buf[0] = 0; /* spare digit for later rounding */ - res_digits = res_buf + 1; + alloc_var(result, res_ndigits); + res_digits = result->digits; /* * Now compute the quotient digits. This is the short division algorithm @@ -9552,9 +9656,7 @@ div_var_int(const NumericVar *var, int ival, int ival_weight, } /* Store the quotient in result */ - digitbuf_free(result->buf); result->ndigits = res_ndigits; - result->buf = res_buf; result->digits = res_digits; result->weight = res_weight; result->sign = res_sign; @@ -9589,11 +9691,12 @@ div_var_int64(const NumericVar *var, int64 ival, int ival_weight, int res_sign; int res_weight; int res_ndigits; - NumericDigit *res_buf; NumericDigit *res_digits; uint64 divisor; int i; + Assert(var != result); + /* Guard against division by zero */ if (ival == 0) ereport(ERROR, @@ -9626,9 +9729,8 @@ div_var_int64(const NumericVar *var, int64 ival, int ival_weight, if (round) res_ndigits++; - res_buf = digitbuf_alloc(res_ndigits + 1); - res_buf[0] = 0; /* spare digit for later rounding */ - res_digits = res_buf + 1; + alloc_var(result, res_ndigits); + res_digits = result->digits; /* * Now compute the quotient digits. This is the short division algorithm @@ -9668,9 +9770,7 @@ div_var_int64(const NumericVar *var, int64 ival, int ival_weight, } /* Store the quotient in result */ - digitbuf_free(result->buf); result->ndigits = res_ndigits; - result->buf = res_buf; result->digits = res_digits; result->weight = res_weight; result->sign = res_sign; @@ -9796,9 +9896,11 @@ div_mod_var(const NumericVar *var1, const NumericVar *var2, { NumericVar q; NumericVar r; + NumericVar tmp_var; init_var(&q); init_var(&r); + init_var(&tmp_var); /* * Use div_var_fast() to get an initial estimate for the integer quotient. @@ -9809,7 +9911,8 @@ div_mod_var(const NumericVar *var1, const NumericVar *var2, /* Compute initial estimate of remainder using the quotient estimate. */ mul_var(var2, &q, &r, var2->dscale); - sub_var(var1, &r, &r); + set_var_from_var(&r, &tmp_var); + sub_var(var1, &tmp_var, &r); /* * Adjust the results if necessary --- the remainder should have the same @@ -9821,13 +9924,17 @@ div_mod_var(const NumericVar *var1, const NumericVar *var2, /* The absolute value of the quotient is too large */ if (var1->sign == var2->sign) { - sub_var(&q, &const_one, &q); - add_var(&r, var2, &r); + set_var_from_var(&q, &tmp_var); + sub_var(&tmp_var, &const_one, &q); + set_var_from_var(&r, &tmp_var); + add_var(&tmp_var, var2, &r); } else { - add_var(&q, &const_one, &q); - sub_var(&r, var2, &r); + set_var_from_var(&q, &tmp_var); + add_var(&tmp_var, &const_one, &q); + set_var_from_var(&r, &tmp_var); + sub_var(&tmp_var, var2, &r); } } @@ -9836,13 +9943,17 @@ div_mod_var(const NumericVar *var1, const NumericVar *var2, /* The absolute value of the quotient is too small */ if (var1->sign == var2->sign) { - add_var(&q, &const_one, &q); - sub_var(&r, var2, &r); + set_var_from_var(&q, &tmp_var); + add_var(&tmp_var, &const_one, &q); + set_var_from_var(&r, &tmp_var); + sub_var(&tmp_var, var2, &r); } else { - sub_var(&q, &const_one, &q); - add_var(&r, var2, &r); + set_var_from_var(&q, &tmp_var); + sub_var(&tmp_var, &const_one, &q); + set_var_from_var(&r, &tmp_var); + add_var(&tmp_var, var2, &r); } } @@ -9851,6 +9962,7 @@ div_mod_var(const NumericVar *var1, const NumericVar *var2, free_var(&q); free_var(&r); + free_var(&tmp_var); } @@ -9871,9 +9983,10 @@ ceil_var(const NumericVar *var, NumericVar *result) trunc_var(&tmp, 0); if (var->sign == NUMERIC_POS && cmp_var(var, &tmp) != 0) - add_var(&tmp, &const_one, &tmp); + add_var(&tmp, &const_one, result); + else + set_var_from_var(&tmp, result); - set_var_from_var(&tmp, result); free_var(&tmp); } @@ -9895,9 +10008,10 @@ floor_var(const NumericVar *var, NumericVar *result) trunc_var(&tmp, 0); if (var->sign == NUMERIC_NEG && cmp_var(var, &tmp) != 0) - sub_var(&tmp, &const_one, &tmp); + sub_var(&tmp, &const_one, result); + else + set_var_from_var(&tmp, result); - set_var_from_var(&tmp, result); free_var(&tmp); } @@ -9997,6 +10111,7 @@ sqrt_var(const NumericVar *arg, NumericVar *result, int rscale) NumericVar a1_var; NumericVar q_var; NumericVar u_var; + NumericVar tmp_var; stat = cmp_var(arg, &const_zero); if (stat == 0) @@ -10021,6 +10136,7 @@ sqrt_var(const NumericVar *arg, NumericVar *result, int rscale) init_var(&a1_var); init_var(&q_var); init_var(&u_var); + init_var(&tmp_var); /* * The result weight is half the input weight, rounded towards minus @@ -10388,13 +10504,15 @@ sqrt_var(const NumericVar *arg, NumericVar *result, int rscale) /* Compute (q,u) = DivRem(r*b + a1, 2*s) */ set_var_from_var(&r_var, &q_var); q_var.weight += blen; - add_var(&q_var, &a1_var, &q_var); + set_var_from_var(&q_var, &tmp_var); + add_var(&tmp_var, &a1_var, &q_var); add_var(&s_var, &s_var, &u_var); div_mod_var(&q_var, &u_var, &q_var, &u_var); /* Compute s = s*b + q */ s_var.weight += blen; - add_var(&s_var, &q_var, &s_var); + set_var_from_var(&s_var, &tmp_var); + add_var(&tmp_var, &q_var, &s_var); /* * Compute r = u*b + a0 - q^2. @@ -10404,7 +10522,8 @@ sqrt_var(const NumericVar *arg, NumericVar *result, int rscale) * So instead of the final subtraction we can just compare. */ u_var.weight += blen; - add_var(&u_var, &a0_var, &u_var); + set_var_from_var(&u_var, &tmp_var); + add_var(&tmp_var, &a0_var, &u_var); mul_var(&q_var, &q_var, &q_var, 0); if (step > 0) @@ -10414,16 +10533,22 @@ sqrt_var(const NumericVar *arg, NumericVar *result, int rscale) if (r_var.sign == NUMERIC_NEG) { /* s is too large by 1; set r += s, s--, r += s */ - add_var(&r_var, &s_var, &r_var); - sub_var(&s_var, &const_one, &s_var); - add_var(&r_var, &s_var, &r_var); + set_var_from_var(&r_var, &tmp_var); + add_var(&tmp_var, &s_var, &r_var); + set_var_from_var(&s_var, &tmp_var); + sub_var(&tmp_var, &const_one, &s_var); + set_var_from_var(&r_var, &tmp_var); + add_var(&tmp_var, &s_var, &r_var); } } else { /* Don't need r anymore, except to test if s is too large by 1 */ if (cmp_var(&u_var, &q_var) < 0) - sub_var(&s_var, &const_one, &s_var); + { + set_var_from_var(&s_var, &tmp_var); + sub_var(&tmp_var, &const_one, &s_var); + } } Assert(src_idx == src_ndigits); /* All input digits consumed */ @@ -10461,6 +10586,7 @@ static void exp_var(const NumericVar *arg, NumericVar *result, int rscale) { NumericVar x; + NumericVar xx; NumericVar elem; int ni; double val; @@ -10470,6 +10596,7 @@ exp_var(const NumericVar *arg, NumericVar *result, int rscale) int local_rscale; init_var(&x); + init_var(&xx); init_var(&elem); set_var_from_var(arg, &x); @@ -10515,7 +10642,8 @@ exp_var(const NumericVar *arg, NumericVar *result, int rscale) } local_rscale = x.dscale + ndiv2; - div_var_int(&x, 1 << ndiv2, 0, &x, local_rscale, true); + set_var_from_var(&x, &xx); + div_var_int(&xx, 1 << ndiv2, 0, &x, local_rscale, true); } else ndiv2 = 0; @@ -10544,15 +10672,18 @@ exp_var(const NumericVar *arg, NumericVar *result, int rscale) mul_var(&x, &x, &elem, local_rscale); ni = 2; - div_var_int(&elem, ni, 0, &elem, local_rscale, true); + set_var_from_var(&elem, &xx); + div_var_int(&xx, ni, 0, &elem, local_rscale, true); while (elem.ndigits != 0) { - add_var(result, &elem, result); + set_var_from_var(result, &xx); + add_var(&xx, &elem, result); mul_var(&elem, &x, &elem, local_rscale); ni++; - div_var_int(&elem, ni, 0, &elem, local_rscale, true); + set_var_from_var(&elem, &xx); + div_var_int(&xx, ni, 0, &elem, local_rscale, true); } /* @@ -10673,6 +10804,7 @@ ln_var(const NumericVar *arg, NumericVar *result, int rscale) { NumericVar x; NumericVar xx; + NumericVar xxx; int ni; NumericVar elem; NumericVar fact; @@ -10692,6 +10824,7 @@ ln_var(const NumericVar *arg, NumericVar *result, int rscale) init_var(&x); init_var(&xx); + init_var(&xxx); init_var(&elem); init_var(&fact); @@ -10748,7 +10881,8 @@ ln_var(const NumericVar *arg, NumericVar *result, int rscale) sub_var(&x, &const_one, result); add_var(&x, &const_one, &elem); - div_var_fast(result, &elem, result, local_rscale, true); + set_var_from_var(result, &xxx); + div_var_fast(&xxx, &elem, result, local_rscale, true); set_var_from_var(result, &xx); mul_var(result, result, &x, local_rscale); @@ -10763,7 +10897,8 @@ ln_var(const NumericVar *arg, NumericVar *result, int rscale) if (elem.ndigits == 0) break; - add_var(result, &elem, result); + set_var_from_var(result, &xxx); + add_var(&xxx, &elem, result); if (elem.weight < (result->weight - local_rscale * 2 / DEC_DIGITS)) break; @@ -10774,6 +10909,7 @@ ln_var(const NumericVar *arg, NumericVar *result, int rscale) free_var(&x); free_var(&xx); + free_var(&xxx); free_var(&elem); free_var(&fact); } @@ -11196,13 +11332,16 @@ power_var_int(const NumericVar *base, int exp, int exp_dscale, } } - free_var(&base_prod); - /* Compensate for input sign, and round to requested rscale */ if (neg) - div_var_fast(&const_one, result, result, rscale, true); + { + div_var_fast(&const_one, result, &base_prod, rscale, true); + set_var_from_var(&base_prod, result); + } else round_var(result, rscale); + + free_var(&base_prod); } /* @@ -11333,7 +11472,6 @@ cmp_abs_common(const NumericDigit *var1digits, int var1ndigits, int var1weight, static void add_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result) { - NumericDigit *res_buf; NumericDigit *res_digits; int res_ndigits; int res_weight; @@ -11352,6 +11490,9 @@ add_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result) NumericDigit *var1digits = var1->digits; NumericDigit *var2digits = var2->digits; + Assert(var1 != result); + Assert(var2 != result); + res_weight = Max(var1->weight, var2->weight) + 1; res_dscale = Max(var1->dscale, var2->dscale); @@ -11365,9 +11506,8 @@ add_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result) if (res_ndigits <= 0) res_ndigits = 1; - res_buf = digitbuf_alloc(res_ndigits + 1); - res_buf[0] = 0; /* spare digit for later rounding */ - res_digits = res_buf + 1; + alloc_var(result, res_ndigits); + res_digits = result->digits; i1 = res_rscale + var1->weight + 1; i2 = res_rscale + var2->weight + 1; @@ -11394,10 +11534,7 @@ add_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result) Assert(carry == 0); /* else we failed to allow for carry out */ - digitbuf_free(result->buf); result->ndigits = res_ndigits; - result->buf = res_buf; - result->digits = res_digits; result->weight = res_weight; result->dscale = res_dscale; @@ -11418,7 +11555,6 @@ add_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result) static void sub_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result) { - NumericDigit *res_buf; NumericDigit *res_digits; int res_ndigits; int res_weight; @@ -11437,6 +11573,9 @@ sub_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result) NumericDigit *var1digits = var1->digits; NumericDigit *var2digits = var2->digits; + Assert(var1 != result); + Assert(var2 != result); + res_weight = var1->weight; res_dscale = Max(var1->dscale, var2->dscale); @@ -11450,9 +11589,8 @@ sub_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result) if (res_ndigits <= 0) res_ndigits = 1; - res_buf = digitbuf_alloc(res_ndigits + 1); - res_buf[0] = 0; /* spare digit for later rounding */ - res_digits = res_buf + 1; + alloc_var(result, res_ndigits); + res_digits = result->digits; i1 = res_rscale + var1->weight + 1; i2 = res_rscale + var2->weight + 1; @@ -11479,10 +11617,7 @@ sub_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result) Assert(borrow == 0); /* else caller gave us var1 < var2 */ - digitbuf_free(result->buf); result->ndigits = res_ndigits; - result->buf = res_buf; - result->digits = res_digits; result->weight = res_weight; result->dscale = res_dscale; @@ -11960,6 +12095,7 @@ accum_sum_final(NumericSumAccum *accum, NumericVar *result) pos_var.buf = pos_var.digits = digitbuf_alloc(accum->ndigits); neg_var.buf = neg_var.digits = digitbuf_alloc(accum->ndigits); + pos_var.buf_len = neg_var.buf_len = accum->ndigits; for (i = 0; i < accum->ndigits; i++) {