summaryrefslogtreecommitdiff
path: root/strings/decimal.c
diff options
context:
space:
mode:
authorAlexey Kopytov <Alexey.Kopytov@Sun.com>2009-12-22 19:23:13 +0300
committerAlexey Kopytov <Alexey.Kopytov@Sun.com>2009-12-22 19:23:13 +0300
commit12f364ece7663663cabdc29f106ca69af63fe4e7 (patch)
tree40437c602d2a9ddaa03a54742cec4884f0974253 /strings/decimal.c
parentd4f23f0cf6db38731a161c5c7b0b056fc67e5c02 (diff)
downloadmariadb-git-12f364ece7663663cabdc29f106ca69af63fe4e7.tar.gz
Backport of WL #2934: Make/find library for doing float/double
to string conversions and vice versa" Initial import of the dtoa.c code and custom wrappers around it to allow its usage from the server code. Conversion of FLOAT/DOUBLE values to DECIMAL ones or strings and vice versa has been significantly reworked. As the new algoritms are more precise than the older ones, results of such conversions may not always match those obtained from older server versions. This in turn may break compatibility for some applications. This patch also fixes the following bugs: - bug #12860 "Difference in zero padding of exponent between Unix and Windows" - bug #21497 "DOUBLE truncated to unusable value" - bug #26788 "mysqld (debug) aborts when inserting specific numbers into char fields" - bug #24541 "Data truncated..." on decimal type columns without any good reason"
Diffstat (limited to 'strings/decimal.c')
-rw-r--r--strings/decimal.c45
1 files changed, 14 insertions, 31 deletions
diff --git a/strings/decimal.c b/strings/decimal.c
index 282e7cae8ab..42dc33e5ac6 100644
--- a/strings/decimal.c
+++ b/strings/decimal.c
@@ -137,12 +137,6 @@ 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)
@@ -947,33 +941,25 @@ fatal_error:
to - result will be stored there
RETURN VALUE
- E_DEC_OK
+ E_DEC_OK/E_DEC_OVERFLOW/E_DEC_TRUNCATED
*/
int decimal2double(decimal_t *from, double *to)
{
- 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]));
+ char strbuf[FLOATING_POINT_BUFFER], *end;
+ int len= sizeof(strbuf);
+ int rc, error;
- result/= scaler10[exp / 10] * scaler1[exp % 10];
-
- *to= from->sign ? -result : result;
+ rc = decimal2string(from, strbuf, &len, 0, 0, 0);
+ end= strbuf + len;
+
+ DBUG_PRINT("info", ("interm.: %s", strbuf));
+ *to= my_strtod(strbuf, &end, &error);
+
DBUG_PRINT("info", ("result: %f (%lx)", *to, *(ulong *)to));
- return E_DEC_OK;
+ return (rc != E_DEC_OK) ? rc : (error ? E_DEC_OVERFLOW : E_DEC_OK);
}
/*
@@ -990,13 +976,10 @@ int decimal2double(decimal_t *from, double *to)
int double2decimal(double from, decimal_t *to)
{
- /* TODO: fix it, when we'll have dtoa */
- char buff[400], *end;
- int length, res;
+ char buff[FLOATING_POINT_BUFFER], *end;
+ int res;
DBUG_ENTER("double2decimal");
- length= my_sprintf(buff, (buff, "%.16G", from));
- DBUG_PRINT("info",("from: %g from_as_str: %s", from, buff));
- end= buff+length;
+ end= buff + my_gcvt(from, MY_GCVT_ARG_DOUBLE, sizeof(buff) - 1, buff, NULL);
res= string2decimal(buff, to, &end);
DBUG_PRINT("exit", ("res: %d", res));
DBUG_RETURN(res);