diff options
author | unknown <tsmith/tim@siva.hindu.god> | 2006-12-19 17:42:26 -0700 |
---|---|---|
committer | unknown <tsmith/tim@siva.hindu.god> | 2006-12-19 17:42:26 -0700 |
commit | fe3672d28570eb552786cb3c5c179f205ed73324 (patch) | |
tree | 398198c9dfb9c94df9552a810de7ee598c267f9c /strings | |
parent | f8920dd59f87f488435f7f60939ed63e0a4b6b52 (diff) | |
download | mariadb-git-fe3672d28570eb552786cb3c5c179f205ed73324.tar.gz |
Alternative decimal2double implementation using an algorithm
more similar to my_strtod() (and maybe even a bit faster due
to less floating point divisions).
This should at least partially fix Bug #23260 for DECIMALs
with a moderate number of total digits.
Diffstat (limited to 'strings')
-rw-r--r-- | strings/decimal.c | 34 |
1 files changed, 26 insertions, 8 deletions
diff --git a/strings/decimal.c b/strings/decimal.c index 6b7a2266194..bdc3b1eef42 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -138,6 +138,12 @@ static const dec1 frac_max[DIG_PER_DEC1-1]={ 900000000, 990000000, 999000000, 999900000, 999990000, 999999000, 999999900, 999999990 }; +static double scaler10[]= { + 1.0, 1e10, 1e20, 1e30, 1e40, 1e50, 1e60, 1e70, 1e80, 1e90 +}; +static double scaler1[]= { + 1.0, 10.0, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9 +}; #ifdef HAVE_purify #define sanity(d) DBUG_ASSERT((d)->len > 0) @@ -946,15 +952,27 @@ fatal_error: int decimal2double(decimal_t *from, double *to) { - double x=0, t=DIG_BASE; - int intg, frac; - dec1 *buf=from->buf; + double result= 0.0; + int i, exp= 0; + dec1 *buf= from->buf; + + for (i= from->intg; i > 0; i-= DIG_PER_DEC1) + result= result * DIG_BASE + *buf++; + + for (i= from->frac; i > 0; i-= DIG_PER_DEC1) { + result= result * DIG_BASE + *buf++; + exp+= DIG_PER_DEC1; + } + + DBUG_PRINT("info", ("interm.: %f %d %f", result, exp, + scaler10[exp / 10] * scaler1[exp % 10])); + + result/= scaler10[exp / 10] * scaler1[exp % 10]; + + *to= from->sign ? -result : result; + + DBUG_PRINT("info", ("result: %f (%lx)", *to, *to)); - for (intg=from->intg; intg > 0; intg-=DIG_PER_DEC1) - x=x*DIG_BASE + *buf++; - for (frac=from->frac; frac > 0; frac-=DIG_PER_DEC1, t*=DIG_BASE) - x+=*buf++/t; - *to=from->sign ? -x : x; return E_DEC_OK; } |