Skip to content

Instantly share code, notes, and snippets.

@joelonsql
Last active February 20, 2023 21:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joelonsql/59bd2642d577fe4aaf2fb8b1ab7f67c4 to your computer and use it in GitHub Desktop.
Save joelonsql/59bd2642d577fe4aaf2fb8b1ab7f67c4 to your computer and use it in GitHub Desktop.
0005-fixed-buf.patch
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++)
{
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment