diff options
author | Tor Didriksen <tor.didriksen@oracle.com> | 2012-11-29 17:21:36 +0100 |
---|---|---|
committer | Tor Didriksen <tor.didriksen@oracle.com> | 2012-11-29 17:21:36 +0100 |
commit | fee6968b426d80c0ec8807833c6cb343d1f8b0b7 (patch) | |
tree | 2ff057dc3e72f966b55aba1acaf280d98e915707 /strings | |
parent | 387ffaa9e1cc61b7ed7a73df7987efaa912da573 (diff) | |
download | mariadb-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.c | 33 |
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; } } } |