msvcrt: Correct implementation of _ecvt() with tests.

This commit is contained in:
Rein Klazes 2009-04-13 09:06:41 +02:00 committed by Alexandre Julliard
parent e014484a43
commit 1ab5f4191d
2 changed files with 117 additions and 6 deletions

View File

@ -836,16 +836,42 @@ double CDECL _nextafter(double num, double next)
*/
char * CDECL _ecvt( double number, int ndigits, int *decpt, int *sign )
{
int prec;
thread_data_t *data = msvcrt_get_thread_data();
char *dec;
/* FIXME: check better for overflow (native supports over 300 chars's) */
ndigits = min( ndigits, 80 - 7); /* 7 : space for dec point, 1 for "e",
* 4 for exponent and one for
* terminating '\0' */
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;
if( number < 0) {
*sign = TRUE;
number = -number;
} else
*sign = FALSE;
/* handle cases with zero ndigits or less */
prec = ndigits;
if( prec < 1) prec = 2;
snprintf(data->efcvt_buffer, 80, "%.*le", prec - 1, number);
/* take the decimal "point away */
if( prec != 1)
strcpy( data->efcvt_buffer + 1, data->efcvt_buffer + 2);
/* take the exponential "e" out */
data->efcvt_buffer[ prec] = '\0';
/* read the exponent */
sscanf( data->efcvt_buffer + prec + 1, "%d", decpt);
(*decpt)++;
/* adjust for some border cases */
if( data->efcvt_buffer[0] == '0')/* value is zero */
*decpt = 0;
/* handle cases with zero ndigits or less */
if( ndigits < 1){
if( data->efcvt_buffer[ 0] >= '5')
(*decpt)++;
data->efcvt_buffer[ 0] = '\0';
}
TRACE("out=\"%s\"\n",data->efcvt_buffer);
return data->efcvt_buffer;
}

View File

@ -698,6 +698,90 @@ static void test_fcvt(void)
ok( 0 == sign, "sign wrong\n");
}
static struct {
double value;
int nrdigits;
const char *expstr_e;
const char *expstr_f;
int expdecpt_e;
int expdecpt_f;
int expsign;
} test_cvt_testcases[] = {
{ 45.0, 2, "45", "4500", 2, 2, 0 },
/* Numbers less than 1.0 with different precisions */
{ 0.0001, 1, "1", "", -3, -3, 0 },
{ 0.0001, -10, "", "", -3, -3, 0 },
{ 0.0001, 10,"1000000000", "1000000", -3, -3, 0 },
/* Basic sign test */
{ -111.0001, 5, "11100", "11100010", 3, 3, 1 },
{ 111.0001, 5, "11100", "11100010", 3, 3, 0 },
/* big numbers with low precision */
{ 3333.3, 2, "33", "333330", 4, 4, 0 },
{999999999999.9, 3, "100","999999999999900", 13, 12, 0 },
/* 0.0 with different precisions */
{ 0.0, 5, "00000", "00000", 0, 0, 0 },
{ 0.0, 0, "", "", 0, 0, 0 },
{ 0.0, -1, "", "", 0, 0, 0 },
/* Numbers > 1.0 with 0 or -ve precision */
{ -123.0001, 0, "", "123", 3, 3, 1 },
{ -123.0001, -1, "", "12", 3, 3, 1 },
{ -123.0001, -2, "", "1", 3, 3, 1 },
{ -123.0001, -3, "", "", 3, 3, 1 },
/* Numbers > 1.0, but with rounding at the point of precision */
{ 99.99, 1, "1", "1000", 3, 3, 0 },
/* Numbers < 1.0 where rounding occurs at the point of precision */
{ 0.0063, 2, "63", "1", -2, -1, 0 },
{ 0.0063, 3, "630", "6", -2, -2, 0 },
{ 0.09999999996, 2, "10", "10", 0, 0, 0 },
{ 0.6, 1, "6", "6", 0, 0, 0 },
{ 0.6, 0, "", "1", 1, 1, 0 },
{ 0.4, 0, "", "", 0, 0, 0 },
{ 0.49, 0, "", "", 0, 0, 0 },
{ 0.51, 0, "", "1", 1, 1, 0 },
/* ask ridiculous amunt of precision, ruin formatting this table */
{ 1.0, 30, "100000000000000000000000000000",
"1000000000000000000000000000000", 1, 1, 0},
{ 123456789012345678901.0, 30, "123456789012345680000000000000",
"123456789012345680000000000000000000000000000000000", 21, 21, 0},
/* end marker */
{ 0, 0, "END"}
};
static void test_xcvt(void)
{
char *str;
int i, decpt, sign;
for( i = 0; strcmp( test_cvt_testcases[i].expstr_e, "END"); i++){
decpt = sign = 100;
str = _ecvt( test_cvt_testcases[i].value,
test_cvt_testcases[i].nrdigits,
&decpt,
&sign);
ok( 0 == strncmp( str, test_cvt_testcases[i].expstr_e, 15),
"_ecvt() bad return, got \n'%s' expected \n'%s'\n", str,
test_cvt_testcases[i].expstr_e);
ok( decpt == test_cvt_testcases[i].expdecpt_e,
"_ecvt() decimal point wrong, got %d expected %d\n", decpt,
test_cvt_testcases[i].expdecpt_e);
}
for( i = 0; strcmp( test_cvt_testcases[i].expstr_e, "END"); i++){
decpt = sign = 100;
str = _fcvt( test_cvt_testcases[i].value,
test_cvt_testcases[i].nrdigits,
&decpt,
&sign);
ok( 0 == strncmp( str, test_cvt_testcases[i].expstr_f, 15),
"_fcvt() bad return, got \n'%s' expected \n'%s'\n", str,
test_cvt_testcases[i].expstr_f);
ok( decpt == test_cvt_testcases[i].expdecpt_f,
"_fcvt() decimal point wrong, got %d expected %d\n", decpt,
test_cvt_testcases[i].expdecpt_f);
ok( sign == test_cvt_testcases[i].expsign,
"_ecvt() sign wrong, got %d expected %d\n", sign,
test_cvt_testcases[i].expsign);
}
}
static int _vsnwprintf_wrapper(wchar_t *str, size_t len, const wchar_t *format, ...)
{
int ret;
@ -774,6 +858,7 @@ START_TEST(printf)
test_swprintf();
test_snprintf();
test_fcvt();
test_xcvt();
test_vsnwprintf();
p__vscprintf = (void *)GetProcAddress(GetModuleHandle("msvcrt.dll"), "_vscprintf");