From: Date: March 31 2005 5:46pm Subject: bk commit into 5.0 tree (serg:1.1843) BUG#9501 List-Archive: http://lists.mysql.com/internals/23532 X-Bug: 9501 Message-Id: <20050331154646.83352.qmail@serg.mysql.com> 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);