summaryrefslogtreecommitdiff
path: root/strings
diff options
context:
space:
mode:
authorTor Didriksen <tor.didriksen@oracle.com>2012-11-29 17:21:36 +0100
committerTor Didriksen <tor.didriksen@oracle.com>2012-11-29 17:21:36 +0100
commitfee6968b426d80c0ec8807833c6cb343d1f8b0b7 (patch)
tree2ff057dc3e72f966b55aba1acaf280d98e915707 /strings
parent387ffaa9e1cc61b7ed7a73df7987efaa912da573 (diff)
downloadmariadb-git-fee6968b426d80c0ec8807833c6cb343d1f8b0b7.tar.gz
Bug#11754279 SIGNIFICANT INACCURACY IN DECIMAL MULTIPLICATION CALCULATIONS
frac is the number of decimal digits after the point For each multiplication in the expression, decimal_mul() does this: to->frac= from1->frac + from2->frac; /* store size in digits */ which will eventually overflow. The code for handling the overflow, will truncate the two digits in "1.75" to "1" Solution: Truncate to 31 significant fractional digits, when doing decimal multiplication.
Diffstat (limited to 'strings')
-rw-r--r--strings/decimal.c33
1 files changed, 17 insertions, 16 deletions
diff --git a/strings/decimal.c b/strings/decimal.c
index 3a170728546..4790ed70f42 100644
--- a/strings/decimal.c
+++ b/strings/decimal.c
@@ -1989,44 +1989,45 @@ int decimal_mul(const decimal_t *from1, const decimal_t *from2, decimal_t *to)
int intg1=ROUND_UP(from1->intg), intg2=ROUND_UP(from2->intg),
frac1=ROUND_UP(from1->frac), frac2=ROUND_UP(from2->frac),
intg0=ROUND_UP(from1->intg+from2->intg),
- frac0=frac1+frac2, error, i, j, d_to_move;
+ frac0=frac1+frac2, error, iii, jjj, d_to_move;
dec1 *buf1=from1->buf+intg1, *buf2=from2->buf+intg2, *buf0,
*start2, *stop2, *stop1, *start0, carry;
sanity(to);
- i=intg0; /* save 'ideal' values */
- j=frac0;
+ iii= intg0; /* save 'ideal' values */
+ jjj= frac0;
FIX_INTG_FRAC_ERROR(to->len, intg0, frac0, error); /* bound size */
- to->sign=from1->sign != from2->sign;
- to->frac=from1->frac+from2->frac; /* store size in digits */
+ to->sign= from1->sign != from2->sign;
+ to->frac= from1->frac + from2->frac; /* store size in digits */
+ set_if_smaller(to->frac, NOT_FIXED_DEC);
to->intg=intg0*DIG_PER_DEC1;
if (unlikely(error))
{
set_if_smaller(to->frac, frac0*DIG_PER_DEC1);
set_if_smaller(to->intg, intg0*DIG_PER_DEC1);
- if (unlikely(i > intg0)) /* bounded integer-part */
+ if (unlikely(iii > intg0)) /* bounded integer-part */
{
- i-=intg0;
- j=i >> 1;
- intg1-= j;
- intg2-=i-j;
+ iii-=intg0;
+ jjj= iii >> 1;
+ intg1-= jjj;
+ intg2-=iii-jjj;
frac1=frac2=0; /* frac0 is already 0 here */
}
else /* bounded fract part */
{
- j-=frac0;
- i=j >> 1;
+ jjj-=frac0;
+ iii=jjj >> 1;
if (frac1 <= frac2)
{
- frac1-= i;
- frac2-=j-i;
+ frac1-= iii;
+ frac2-=jjj-iii;
}
else
{
- frac2-= i;
- frac1-=j-i;
+ frac2-= iii;
+ frac1-=jjj-iii;
}
}
}