- Implement higher precision exponent selection, checked against ecvt test cases to match wanted behavior
- msvcrt printf winetests up by ~10 because current ecvt relies on non-correct behavior
- Cleanup unneeded checks, wrong variable usages, add new header

svn path=/trunk/; revision=42382
This commit is contained in:
Gregor Schneider 2009-08-04 15:09:47 +00:00
parent a1c98e143e
commit a08bde0eb5

View file

@ -1,21 +1,17 @@
/* /*
* PROGRAMMERS: * COPYRIGHT: See COPYING in the top level directory
* David Welch * PURPOSE: CRT's vsnprintf
* Eric Kohl * FILE: lib/sdk/crt/stdio/lnx_printf.c
* Gregor Schneider * PROGRAMERS: David Welch
* Eric Kohl
Gregor Schneider
* TODO: * TODO:
* - Verify the implementation of '%Z'. * - Verify the implementation of '%Z'.
*/ */
/* /*
* linux/lib/vsprintf.c * Parts from linux/lib/vsprintf.c
* * Lars Wirzenius & Linus Torvalds
* Copyright (C) 1991, 1992 Linus Torvalds
*/
/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
/*
* Wirzenius wrote this portably, Torvalds fucked it up :-) * Wirzenius wrote this portably, Torvalds fucked it up :-)
*/ */
@ -156,11 +152,49 @@ typedef struct {
unsigned int sign:1; unsigned int sign:1;
} ieee_double_t; } ieee_double_t;
static __inline void fracrnd(double *number, int prec)
{
/* Shifts fractional digits to decimal places and compares to round table */
/* Only suitable to determine the exponent with more precision, not for normal rounding */
/* Incoming numbers are expected to range from approx -10.0 to 10.0 */
int lpos = 1, ubound, sign = 1;
long decimal = abs((long)*number);
double frac = (*number - decimal) * 10;
long rt[] =
{
0,
9,
99,
999,
9999,
99999,
999999,
9999999,
99999999,
999999999
};
if (*number < 0)
{
sign = -1;
}
ubound = min(prec, sizeof(rt)/sizeof(*rt) - 1);
while ((long)frac % 10 != 0 && lpos < ubound)
{
frac *= 10;
lpos++;
}
if (abs((long)frac) == rt[lpos])
{
*number = sign * (decimal + 1);
}
}
static char * static char *
numberf(char * buf, char * end, double num, char exp_sign, int size, int precision, int type) numberf(char * buf, char * end, double num, char exp_sign, int size, int precision, int type)
{ {
double exponent = 0.0; double exponent = 0.0;
double e; double e = 0.0;
long ie; long ie;
int i = 0; int i = 0;
@ -185,9 +219,7 @@ numberf(char * buf, char * end, double num, char exp_sign, int size, int precisi
if ( exp_sign == 'g' || exp_sign == 'G' || exp_sign == 'e' || exp_sign == 'E' ) if ( exp_sign == 'g' || exp_sign == 'G' || exp_sign == 'e' || exp_sign == 'E' )
{ {
ie = ((unsigned int)n.n->exponent - (unsigned int)0x3ff); ie = ((unsigned int)n.n->exponent - (unsigned int)0x3ff);
if (*n.__n == 0.0) if (num != 0.0)
exponent = 0.0;
else
{ {
exponent = ie/3.321928; exponent = ie/3.321928;
} }
@ -205,28 +237,25 @@ numberf(char * buf, char * end, double num, char exp_sign, int size, int precisi
if ( exp_sign == 'e' || exp_sign == 'E' ) if ( exp_sign == 'e' || exp_sign == 'E' )
{ {
if (num != 0.0)
{
/* Find a suitable exponent */
frac = modf(exponent, &e); frac = modf(exponent, &e);
if (num < 0.0)
e--;
if (frac >= 0.5)
e++;
else if (frac < -0.5)
e--;
num2 = num/pow(10.0L, (long double)e); num2 = num/pow(10.0L, (long double)e);
/* Check if rounding is possible */
fracrnd(&num2, precision);
if (num2 < 1.0 && num2 > -1.0) if (num2 < 1.0 && num2 > -1.0)
{ {
e--; e--;
num2 = num/pow(10.0L,(long double)e);
} }
else if (num2 < -10.0 && num2 > 10.0) else if (num2 <= -10.0 || num2 >= 10.0)
{ {
e++; e++;
num2 = num/pow(10.0L,(long double)e); }
} }
/* size-5 because "e+abc" is going to follow */ /* size-5 because "e+abc" is going to follow */
buf = numberf(buf, end, num2, 'f', size-5, precision, type); buf = numberf(buf, end, num/pow(10.0L,(long double)e), 'f', size-5, precision, type);
isize = 4; isize = 4;
while(*(buf-1) == ' ') while(*(buf-1) == ' ')
{ {