msvcrt: Make _ecvt and _fcvt work (yet again)
Stephen Moehle
smoehle at comcast.net
Tue Oct 17 01:27:33 CDT 2006
I am resubmitting my patches for _ecvt and _fcvt. They are the same as
before except they are attached to avoid word-wrapping problems. The
patches are alternate ways of implementing _ecvt and _fcvt. The first is
my own implementation. The second uses ecvt_r and fcvt_r from glibc.
Personally, I prefer the second mainly for its simplicity, but my
testing shows my own implementation agrees closely with the versions of
_ecvt and _fcvt in Visual Studio 2005. The existing code had at least
the following problems: added a decimal point to the output, used
scientific notation in the output, did not remove the leading '-' for
negative numbers, and got the decimal point offset wrong for numbers
like 0.0003.
As suggested, I am also attaching the results my testing. My
implementation agrees with VS2005 except in the last case where the 0
padding is wrong for _fcvt. The value and decimal place are still
correct, however. The existing wine implementation is wrong in every
case and never even close. If anyone wants to see the C program, I will
provide it.
Why I created this patch: I noticed that the Topo program (map
viewing/printing from National Geographic, version 3.4.3) was displaying
coordinates using scientific notation and was using two decimal points.
So instead of displaying 38.098 for the latitude, I was seeing
3..8098e+01. I believe this also fixes Bug 6413 in WineHQ Bugzilla.
From: Stephen Moehle <smoehle at comcast.net>
Changelog for my implementation of _ecvt and _fcvt:
msvcrt: Make _ecvt and _fcvt work by largely rewriting them.
Changelog for using ecvt_r and fcvt_r:
msvcrt: Make _ecvt and _fcvt work by using ecvt_r and fcvt_r.
-------------- next part --------------
>From e35a536371239f469ace202dd5a656eac3d8f646 Mon Sep 17 00:00:00 2001
From: Stephen Moehle <smoehle at comcast.net>
Date: Mon, 16 Oct 2006 21:34:06 -0700
Subject: msvcrt: Make _ecvt and _fcvt work by largely rewriting them.
---
dlls/msvcrt/math.c | 93 ++++++++++++++++++++++++++++++++++++++++------------
1 files changed, 72 insertions(+), 21 deletions(-)
diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c
index f06166b..2c07f88 100644
--- a/dlls/msvcrt/math.c
+++ b/dlls/msvcrt/math.c
@@ -20,6 +20,7 @@
#include "config.h"
#include <stdio.h>
+#include <stdlib.h>
#define __USE_ISOC9X 1
#define __USE_ISOC99 1
#include <math.h>
@@ -849,22 +850,67 @@ double CDECL _nextafter(double num, doub
return retval;
}
-/*********************************************************************
- * _ecvt (MSVCRT.@)
- */
-char * CDECL _ecvt( double number, int ndigits, int *decpt, int *sign )
+
+static char *efcvt_helper(double number, int ndigits, int *decpt, int *sign)
{
thread_data_t *data = msvcrt_get_thread_data();
- char *dec;
+ char *exp;
+ char *buf;
if (!data->efcvt_buffer)
data->efcvt_buffer = MSVCRT_malloc( 80 ); /* ought to be enough */
- snprintf(data->efcvt_buffer, 80, "%.*e", ndigits /* FIXME wrong */, number);
- *sign = (number < 0);
- dec = strchr(data->efcvt_buffer, '.');
- *decpt = (dec) ? dec - data->efcvt_buffer : -1;
- return data->efcvt_buffer;
+ buf = data->efcvt_buffer;
+
+ if (ndigits < 15) {
+ ndigits = 15;
+ }
+
+ snprintf(buf, 80, "%.*e", ndigits, number);
+
+ if (*buf == '-') {
+ *sign = 1;
+ ++buf;
+ }
+ else {
+ *sign = 0;
+ }
+
+ exp = strchr(buf, 'e');
+ if (exp) {
+ *decpt = atoi(exp + 1) + 1;
+ *exp = '\0';
+ }
+ else {
+ *decpt = 1;
+ }
+
+ if (*(buf + 1) == '.') {
+ memmove(buf + 1, buf + 2, strlen(buf + 1));
+ }
+
+ return buf;
+}
+
+/*********************************************************************
+ * _ecvt (MSVCRT.@)
+ */
+char * CDECL _ecvt( double number, int ndigits, int *decpt, int *sign )
+{
+ char *buf = efcvt_helper(number, ndigits, decpt, sign);
+ /* manually round to ndigits */
+ if (ndigits == 0) {
+ *buf = '\0';
+ }
+ else {
+ int len = strlen(buf);
+ if (len > ndigits) {
+ double d = atof(buf);
+ d /= pow(10.0, len - ndigits);
+ snprintf(buf, 79, "%.0f", d);
+ }
+ }
+ return buf;
}
/***********************************************************************
@@ -872,17 +918,22 @@ char * CDECL _ecvt( double number, int n
*/
char * CDECL _fcvt( double number, int ndigits, int *decpt, int *sign )
{
- thread_data_t *data = msvcrt_get_thread_data();
- char *dec;
-
- if (!data->efcvt_buffer)
- data->efcvt_buffer = MSVCRT_malloc( 80 ); /* ought to be enough */
-
- snprintf(data->efcvt_buffer, 80, "%.*e", ndigits, number);
- *sign = (number < 0);
- dec = strchr(data->efcvt_buffer, '.');
- *decpt = (dec) ? dec - data->efcvt_buffer : -1;
- return data->efcvt_buffer;
+ char *buf = efcvt_helper(number, ndigits, decpt, sign);
+ /* manually round to ndigits */
+ int len = strlen(buf);
+ int digs = ndigits + *decpt;
+ if (digs < 0) {
+ *buf = '\0';
+ }
+ else if (len > digs) {
+ double d = atof(buf);
+ d /= pow(10.0, len - digs);
+ snprintf(buf, 79, "%.0f", d);
+ if (*buf == '0') {
+ *buf = '\0';
+ }
+ }
+ return buf;
}
/***********************************************************************
--
1.4.2.3
-------------- next part --------------
>From 2e9cbe9d26e569a145df46635b6a9406b9a65351 Mon Sep 17 00:00:00 2001
From: Stephen Moehle <smoehle at comcast.net>
Date: Sun, 15 Oct 2006 20:28:01 -0700
Subject: msvcrt: Make _ecvt and _fcvt work by using ecvt_r and fcvt_r.
---
dlls/msvcrt/math.c | 17 +++++++----------
1 files changed, 7 insertions(+), 10 deletions(-)
diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c
index f06166b..d0d3f29 100644
--- a/dlls/msvcrt/math.c
+++ b/dlls/msvcrt/math.c
@@ -20,6 +20,11 @@
#include "config.h"
#include <stdio.h>
+#ifdef __USE_MISC
+#undef __USE_MISC
+#endif
+#define __USE_MISC
+#include <stdlib.h>
#define __USE_ISOC9X 1
#define __USE_ISOC99 1
#include <math.h>
@@ -855,15 +860,11 @@ double CDECL _nextafter(double num, doub
char * CDECL _ecvt( double number, int ndigits, int *decpt, int *sign )
{
thread_data_t *data = msvcrt_get_thread_data();
- char *dec;
if (!data->efcvt_buffer)
data->efcvt_buffer = MSVCRT_malloc( 80 ); /* ought to be enough */
- snprintf(data->efcvt_buffer, 80, "%.*e", ndigits /* FIXME wrong */, number);
- *sign = (number < 0);
- dec = strchr(data->efcvt_buffer, '.');
- *decpt = (dec) ? dec - data->efcvt_buffer : -1;
+ ecvt_r(number, ndigits, decpt, sign, data->efcvt_buffer, 80);
return data->efcvt_buffer;
}
@@ -873,15 +874,11 @@ char * CDECL _ecvt( double number, int n
char * CDECL _fcvt( double number, int ndigits, int *decpt, int *sign )
{
thread_data_t *data = msvcrt_get_thread_data();
- char *dec;
if (!data->efcvt_buffer)
data->efcvt_buffer = MSVCRT_malloc( 80 ); /* ought to be enough */
- snprintf(data->efcvt_buffer, 80, "%.*e", ndigits, number);
- *sign = (number < 0);
- dec = strchr(data->efcvt_buffer, '.');
- *decpt = (dec) ? dec - data->efcvt_buffer : -1;
+ fcvt_r(number, ndigits, decpt, sign, data->efcvt_buffer, 80);
return data->efcvt_buffer;
}
--
1.4.2.3
-------------- next part --------------
number ndigits
input: 12.34567 4
output decpt sign
vc++ ecvt: 1235 2 0
my ecvt: 1235 2 0
wine ecvt: 1.234567e+001 1 0
vc++ fcvt: 123457 2 0
my fcvt: 123457 2 0
wine fcvt: 1.2346e+001 1 0
input: 12.34567 0
output decpt sign
vc++ ecvt: 2 0
my ecvt: 2 0
wine ecvt: 1.234567e+001 1 0
vc++ fcvt: 12 2 0
my fcvt: 12 2 0
wine fcvt: 1e+001 -1 0
input: -123.4567 8
output decpt sign
vc++ ecvt: 12345670 3 1
my ecvt: 12345670 3 1
wine ecvt: -1.234567e+002 2 1
vc++ fcvt: 12345670000 3 1
my fcvt: 12345670000 3 1
wine fcvt: -1.23456700e+002 2 1
input: .0003 6
output decpt sign
vc++ ecvt: 300000 -3 0
my ecvt: 300000 -3 0
wine ecvt: 3.000000e-004 1 0
vc++ fcvt: 300 -3 0
my fcvt: 300 -3 0
wine fcvt: 3.000000e-004 1 0
input: .0003 4
output decpt sign
vc++ ecvt: 3000 -3 0
my ecvt: 3000 -3 0
wine ecvt: 3.000000e-004 1 0
vc++ fcvt: 3 -3 0
my fcvt: 3 -3 0
wine fcvt: 3.0000e-004 1 0
input: .0003 3
output decpt sign
vc++ ecvt: 300 -3 0
my ecvt: 300 -3 0
wine ecvt: 3.000000e-004 1 0
vc++ fcvt: -3 0
my fcvt: -3 0
wine fcvt: 3.000e-004 1 0
input: .0003 1
output decpt sign
vc++ ecvt: 3 -3 0
my ecvt: 3 -3 0
wine ecvt: 3.000000e-004 1 0
vc++ fcvt: -3 0
my fcvt: -3 0
wine fcvt: 3.0e-004 1 0
input: .0003 0
output decpt sign
vc++ ecvt: -3 0
my ecvt: -3 0
wine ecvt: 3.000000e-004 1 0
vc++ fcvt: -3 0
my fcvt: -3 0
wine fcvt: 3e-004 -1 0
input: 1234567.89 4
output decpt sign
vc++ ecvt: 1235 7 0
my ecvt: 1235 7 0
wine ecvt: 1.234568e+006 1 0
vc++ fcvt: 12345678900 7 0
my fcvt: 12345678900 7 0
wine fcvt: 1.2346e+006 1 0
input: 1234567.89 8
output decpt sign
vc++ ecvt: 12345679 7 0
my ecvt: 12345679 7 0
wine ecvt: 1.234568e+006 1 0
vc++ fcvt: 123456789000000 7 0
my fcvt: 123456789000000 7 0
wine fcvt: 1.23456789e+006 1 0
input: 1234567.89 14
output decpt sign
vc++ ecvt: 12345678900000 7 0
my ecvt: 12345678900000 7 0
wine ecvt: 1.234568e+006 2 0
vc++ fcvt: 123456788999999990000 7 0
my fcvt: 1234567890000000 7 0
wine fcvt: 1.23456789000000e+006 1 0
More information about the wine-patches
mailing list