msvcrt: Correct implementation of _ecvt() with tests.
This commit is contained in:
parent
e014484a43
commit
1ab5f4191d
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in New Issue