Commit 65c3870c authored by Chad MILLER's avatar Chad MILLER

Bug#36270: incorrect calculation result - works in 4.1 but not in 5.0 or 5.1

When the fractional part in a multiplication of DECIMALs
overflowed, we truncated the first operand rather than the
longest. Now truncating least significant places instead
for more precise multiplications.

(Queuing at demand of Trudy/Davi.)

mysql-test/r/type_newdecimal.result:
  show that if we need to truncate the scale of an operand, we pick the
  right one (that is, we discard the least significant decimal places)
mysql-test/t/type_newdecimal.test:
  show that if we need to truncate the scale of an operand, we pick the
  right one (that is, we discard the least significant decimal places)
strings/decimal.c:
  when needing to disregard fractional parts, pick the least
  significant ones
parent 0546add3
...@@ -1519,4 +1519,9 @@ SELECT f1 FROM t1; ...@@ -1519,4 +1519,9 @@ SELECT f1 FROM t1;
f1 f1
99999999999999999999999999999.999999999999999999999999999999 99999999999999999999999999999.999999999999999999999999999999
DROP TABLE t1; DROP TABLE t1;
select (1.20396873 * 0.89550000 * 0.68000000 * 1.08721696 * 0.99500000 *
1.01500000 * 1.01500000 * 0.99500000);
(1.20396873 * 0.89550000 * 0.68000000 * 1.08721696 * 0.99500000 *
1.01500000 * 1.01500000 * 0.99500000)
0.812988073953673124592306939480
End of 5.0 tests End of 5.0 tests
...@@ -1216,4 +1216,13 @@ DESC t1; ...@@ -1216,4 +1216,13 @@ DESC t1;
SELECT f1 FROM t1; SELECT f1 FROM t1;
DROP TABLE t1; DROP TABLE t1;
#
# Bug #36270: incorrect calculation result - works in 4.1 but not in 5.0 or 5.1
#
# show that if we need to truncate the scale of an operand, we pick the
# right one (that is, we discard the least significant decimal places)
select (1.20396873 * 0.89550000 * 0.68000000 * 1.08721696 * 0.99500000 *
1.01500000 * 1.01500000 * 0.99500000);
--echo End of 5.0 tests --echo End of 5.0 tests
...@@ -1999,18 +1999,18 @@ int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to) ...@@ -1999,18 +1999,18 @@ int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to)
sanity(to); sanity(to);
i=intg0; i=intg0; /* save 'ideal' values */
j=frac0; j=frac0;
FIX_INTG_FRAC_ERROR(to->len, intg0, frac0, error); FIX_INTG_FRAC_ERROR(to->len, intg0, frac0, error); /* bound size */
to->sign=from1->sign != from2->sign; to->sign=from1->sign != from2->sign;
to->frac=from1->frac+from2->frac; to->frac=from1->frac+from2->frac; /* store size in digits */
to->intg=intg0*DIG_PER_DEC1; to->intg=intg0*DIG_PER_DEC1;
if (unlikely(error)) if (unlikely(error))
{ {
set_if_smaller(to->frac, frac0*DIG_PER_DEC1); set_if_smaller(to->frac, frac0*DIG_PER_DEC1);
set_if_smaller(to->intg, intg0*DIG_PER_DEC1); set_if_smaller(to->intg, intg0*DIG_PER_DEC1);
if (unlikely(i > intg0)) if (unlikely(i > intg0)) /* bounded integer-part */
{ {
i-=intg0; i-=intg0;
j=i >> 1; j=i >> 1;
...@@ -2018,12 +2018,20 @@ int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to) ...@@ -2018,12 +2018,20 @@ int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to)
intg2-=i-j; intg2-=i-j;
frac1=frac2=0; /* frac0 is already 0 here */ frac1=frac2=0; /* frac0 is already 0 here */
} }
else else /* bounded fract part */
{ {
j-=frac0; j-=frac0;
i=j >> 1; i=j >> 1;
frac1-= i; if (frac1 <= frac2)
frac2-=j-i; {
frac1-= i;
frac2-=j-i;
}
else
{
frac2-= i;
frac1-=j-i;
}
} }
} }
start0=to->buf+intg0+frac0-1; start0=to->buf+intg0+frac0-1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment