Since i have to convert lots of double to char[] very fast, after step into sprintf
, i found that _cfltcvt_l
did the real conversion work, and before _cfltcvt_l
is called, it has many switch
,case
,validate
...function that i don't really need, so i want to convert double to char[] by myself.
I want to get the same result as sprintf(c,"%16.9E",d);
does, for example:
d=49.9999999995; --> c={"5.000000000E+001"}
d=2.5323867855e+298; --> c={"2.532386786e+298"}
Here is my code:
#include<iostream>
using namespace std;
void fast_sprintf(char* c, double d)
{
int i = 0, e = 0, n = 0, flag = 0;//flag=0E+;1E-
if (d < 0)
{
c[i++] = '-';
d = -d;
}
while (d >= 10)
{
d /= 10;//here is the problem
e++;
}
while (d < 1)
{
d *= 10;
e++;
flag = 1;
}
int v = d, dot;
c[i++] = '0' + v;//the integer part
dot = i;
n++;
c[i++] = '.';
d -= v;
while (d != 0 && n < 10)
{
d *= 10;
v = d;
c[i++] = '0' + v;
n++;
d -= v;
}
if (d != 0)
{
if (d * 10 >= 5)//rounding
{
int j = i - 1;
c[j]++;
while (c[j]>'9')
{
c[j] = '0';
if (j - 1 == dot)
j--;
c[--j]++;
}
}
}
else
{
while (n < 10)
{
c[i++] = '0';
n++;
}
}
c[i++] = 'E';
c[i++] = (flag == 0) ? '+' : '-';
if (e >= 100)
{
int tmp = e / 100;
c[i++] = '0' + tmp;
e -= (tmp*100);
c[i++] = '0' + e / 10;
c[i++] = '0' + e % 10;
}
else if (e <= 9)
{
c[i++] = '0';
c[i++] = '0';
c[i++] = '0' + e;
}
else
{
c[i++] = '0';
c[i++] = '0' + e / 10;
c[i++] = '0' + e % 10;
}
c[i] = '\0';
}
int main()
{
char c[20];
//double d=49.9999999995;
double d=2.5323867855e+298;
sprintf(c,"%16.9E",d);
cout<<c<<endl;
fast_sprintf(c,d);
cout<<c<<endl;
return 0;
}
But when d=2.5323867855e+298, c={"2.532386785e+298"} instead of c={"2.532386786e+298"}
That's because after this loop:
//before loop, d=2.5323867855000001e+298
while (d >= 10)
{
d /= 10;//here is the problem
e++;
}
//after loop, d=2.5323867854999969
d loses its precision, the last digit 5 becomes 4999969.
So how can i fix my code or is there a better way to implement another sprintf(c,"%16.9E",d);
?
Thanks.