Below is the list of changes that have just been committed into a local
5.0 repository of serg. When serg does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet
1.1843 05/03/31 17:46:36 serg@stripped +3 -0
decimal_div bug#9501
strings/decimal.c
1.43 05/03/31 17:46:27 serg@stripped +55 -68
decimal_div bug#9501
mysql-test/t/type_newdecimal.test
1.4 05/03/31 17:46:27 serg@stripped +6 -1
decimal_div bug#9501
mysql-test/r/type_newdecimal.result
1.5 05/03/31 17:46:27 serg@stripped +3 -0
decimal_div bug#9501
# This is a BitKeeper patch. What follows are the unified diffs for the
# set of deltas contained in the patch. The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User: serg
# Host: serg.mylan
# Root: /usr/home/serg/Abk/mysql-5.0
--- 1.4/mysql-test/r/type_newdecimal.result Fri Mar 25 14:16:57 2005
+++ 1.5/mysql-test/r/type_newdecimal.result Thu Mar 31 17:46:27 2005
@@ -839,3 +839,6 @@
INSERT INTO Sow6_2f VALUES ('a59b');
ERROR HY000: Incorrect decimal value: 'a59b' for column 'col1' at row 1
drop table Sow6_2f;
+select 10.3330000000000/12.34500000;
+10.3330000000000/12.34500000
+0.8370190360469825840421223160000
--- 1.3/mysql-test/t/type_newdecimal.test Fri Mar 25 14:16:36 2005
+++ 1.4/mysql-test/t/type_newdecimal.test Thu Mar 31 17:46:27 2005
@@ -748,7 +748,7 @@
#+-------+
#| 1 / 0 |
#+-------+
-#| NULL |
+#| NULL |
#+-------+
#1 row in set, 1 warning (0.00 sec)
#
@@ -864,3 +864,8 @@
INSERT INTO Sow6_2f VALUES ('a59b');
#-- should return SQLSTATE 22018 invalid character value for cast
drop table Sow6_2f;
+
+#
+# bug#9501
+#
+select 10.3330000000000/12.34500000;
--- 1.42/strings/decimal.c Mon Mar 21 13:58:29 2005
+++ 1.43/strings/decimal.c Thu Mar 31 17:46:27 2005
@@ -1933,16 +1933,16 @@
XXX if this library is to be used with huge numbers of thousands of
digits, fast division must be implemented and alloca should be
changed to malloc (or at least fallback to malloc if alloca() fails)
- but then, decimal_mod() should be rewritten too :(
+ but then, decimal_mul() should be rewritten too :(
*/
static int do_div_mod(decimal_t *from1, decimal_t *from2,
decimal_t *to, decimal_t *mod, int scale_incr)
{
int frac1=ROUND_UP(from1->frac)*DIG_PER_DEC1, prec1=from1->intg+frac1,
frac2=ROUND_UP(from2->frac)*DIG_PER_DEC1, prec2=from2->intg+frac2,
- error, i, intg0, frac0, len1, len2, dlen1, dintg, div=(!mod);
+ error, i, intg0, frac0, len1, len2, dintg, div=(!mod);
dec1 *buf0, *buf1=from1->buf, *buf2=from2->buf, *tmp1,
- *start2, *stop2, *stop1, *stop0, norm2, carry, *start1;
+ *start2, *stop2, *stop1, *stop0, norm2, carry, *start1, dcarry;
dec2 norm_factor, x, guess, y;
LINT_INIT(error);
@@ -2043,7 +2043,7 @@
/* removing end zeroes */
while (*stop2 == 0 && stop2 >= start2)
stop2--;
- len2= ++stop2 - start2;
+ len2= stop2++ - start2;
/*
calculating norm2 (normalized *start2) - we need *start2 to be large
@@ -2055,87 +2055,70 @@
*/
norm_factor=DIG_BASE/(*start2+1);
norm2=(dec1)(norm_factor*start2[0]);
- if (likely(len2>1))
+ if (likely(len2>0))
norm2+=(dec1)(norm_factor*start2[1]/DIG_BASE);
+ if (*start1 < *start2)
+ dcarry=*start1++;
+ else
+ dcarry=0;
+
/* main loop */
- for ( ; buf0 < stop0; buf0++)
+ for (; buf0 < stop0; buf0++)
{
/* short-circuit, if possible */
- if (unlikely(*start1 == 0))
- {
- start1++;
- if (likely(div))
- *buf0=0;
- continue;
- }
-
- /* D3: make a guess */
- if (*start1 >= *start2)
- {
- x=start1[0];
- y=start1[1];
- dlen1=len2-1;
- }
+ if (unlikely(dcarry == 0 && *start1 < *start2))
+ guess=0;
else
{
- x=((dec2)start1[0])*DIG_BASE+start1[1];
- y=start1[2];
- dlen1=len2;
- }
- guess=(norm_factor*x+norm_factor*y/DIG_BASE)/norm2;
- if (unlikely(guess >= DIG_BASE))
- guess=DIG_BASE-1;
- if (likely(len2>1))
- {
- /* hmm, this is a suspicious trick - I removed normalization here */
- if (start2[1]*guess > (x-guess*start2[0])*DIG_BASE+y)
- guess--;
- if (unlikely(start2[1]*guess > (x-guess*start2[0])*DIG_BASE+y))
- guess--;
- DBUG_ASSERT(start2[1]*guess <= (x-guess*start2[0])*DIG_BASE+y);
- }
-
- /* D4: multiply and subtract */
- buf2=stop2;
- buf1=start1+dlen1;
- DBUG_ASSERT(buf1 < stop1);
- for (carry=0; buf2 > start2; buf1--)
- {
- dec1 hi, lo;
- x=guess * (*--buf2);
- hi=(dec1)(x/DIG_BASE);
- lo=(dec1)(x-((dec2)hi)*DIG_BASE);
- SUB2(*buf1, *buf1, lo, carry);
- carry+=hi;
- }
- for (; buf1 >= start1; buf1--)
- {
- SUB2(*buf1, *buf1, 0, carry);
- }
+ /* D3: make a guess */
+ x=start1[0]+((dec2)dcarry)*DIG_BASE;
+ y=start1[1];
+ guess=(norm_factor*x+norm_factor*y/DIG_BASE)/norm2;
+ if (unlikely(guess >= DIG_BASE))
+ guess=DIG_BASE-1;
+ if (likely(len2>0))
+ {
+ /* hmm, this is a suspicious trick - I removed normalization here */
+ if (start2[1]*guess > (x-guess*start2[0])*DIG_BASE+y)
+ guess--;
+ if (unlikely(start2[1]*guess > (x-guess*start2[0])*DIG_BASE+y))
+ guess--;
+ DBUG_ASSERT(start2[1]*guess <= (x-guess*start2[0])*DIG_BASE+y);
+ }
- /* D5: check the remainder */
- if (unlikely(carry))
- {
- DBUG_ASSERT(carry==1);
- /* D6: correct the guess */
- guess--;
+ /* D4: multiply and subtract */
buf2=stop2;
- buf1=start1+dlen1;
+ buf1=start1+len2;
+ DBUG_ASSERT(buf1 < stop1);
for (carry=0; buf2 > start2; buf1--)
{
- ADD(*buf1, *buf1, *--buf2, carry);
+ dec1 hi, lo;
+ x=guess * (*--buf2);
+ hi=(dec1)(x/DIG_BASE);
+ lo=(dec1)(x-((dec2)hi)*DIG_BASE);
+ SUB2(*buf1, *buf1, lo, carry);
+ carry+=hi;
}
- for (; buf1 >= start1; buf1--)
+ carry= dcarry < carry;
+
+ /* D5: check the remainder */
+ if (unlikely(carry))
{
- SUB2(*buf1, *buf1, 0, carry);
+ /* D6: correct the guess */
+ guess--;
+ buf2=stop2;
+ buf1=start1+len2;
+ for (carry=0; buf2 > start2; buf1--)
+ {
+ ADD(*buf1, *buf1, *--buf2, carry);
+ }
}
- DBUG_ASSERT(carry==1);
}
if (likely(div))
*buf0=(dec1)guess;
- if (*start1 == 0)
- start1++;
+ dcarry= *start1;
+ start1++;
}
if (mod)
{
@@ -2144,6 +2127,8 @@
intg=prec1-frac1
frac=max(frac1, frac2)=to->frac
*/
+ if (dcarry)
+ *--start1=dcarry;
buf0=to->buf;
intg0=ROUND_UP(prec1-frac1)-(start1-tmp1);
frac0=ROUND_UP(to->frac);
@@ -2753,6 +2738,8 @@
test_dv("1.000000000000", "3","0.333333333333333333", 0);
test_dv("1", "1","1.000000000", 0);
test_dv("0.0123456789012345678912345",
"9999999999","0.000000000001234567890246913578148141", 0);
+ test_dv("10.333000000", "12.34500","0.837019036046982584042122316", 0);
+ test_dv("10.000000000060", "2","5.000000000030000000", 0);
printf("==== decimal_mod ====\n");
test_md("234","10","4", 0);
| Thread |
|---|
| • bk commit into 5.0 tree (serg:1.1843) BUG#9501 | Sergei Golubchik | 31 Mar |