#include <stdlib.h>
#include <endian.h>
#include <math.h>
/* convert double to string. Helper for sprintf. */
static int copystring(char* buf,int maxlen, const char* s) {
int i;
for (i=0; i<maxlen; ++i) {
buf[i]=s[i];
if (!s[i])
break;
}
return i;
}
int __dtostr(double d,char *buf,unsigned int maxlen,unsigned int prec,unsigned int prec2,int flags) {
#if 1
union {
unsigned long long l;
double d;
} u = { .d=d };
/* step 1: extract sign, mantissa and exponent */
signed long e=((u.l>>52)&((1<<11)-1))-1023;
#else
#if __BYTE_ORDER == __LITTLE_ENDIAN
signed long e=(((((unsigned long*)&d)[1])>>20)&((1<<11)-1))-1023;
#else
signed long e=(((*((unsigned long*)&d))>>20)&((1<<11)-1))-1023;
#endif
#endif
/* unsigned long long m=u.l & ((1ull<<52)-1); */
/* step 2: exponent is base 2, compute exponent for base 10 */
signed long e10;
/* step 3: calculate 10^e10 */
unsigned int i;
double backup=d;
double tmp;
char *oldbuf=buf;
if (isinf(d))
return copystring(buf,maxlen,
(d<0)?
(flags&0x02?"-INF":"-inf"):
(flags&0x02?"INF":"inf"));
if (isnan(d)) return copystring(buf,maxlen,flags&0x02?"NAN":"nan");
e10=1+(long)(e*0.30102999566398119802); /* log10(2) */
/* Wir iterieren von Links bis wir bei 0 sind oder maxlen erreicht
* ist. Wenn maxlen erreicht ist, machen wir das nochmal in
* scientific notation. Wenn dann von prec noch was übrig ist, geben
* wir einen Dezimalpunkt aus und geben prec2 Nachkommastellen aus.
* Wenn prec2 Null ist, geben wir so viel Stellen aus, wie von prec
* noch übrig ist. */
if (d==0.0) {
prec2=prec2==0?1:prec2+2;
prec2=prec2>maxlen?8:prec2;
i=0;
if (prec2 && (long long)u.l<0) { buf[0]='-'; ++i; }
for (; i<prec2; ++i) buf[i]='0';
buf[buf[0]=='0'?1:2]='.'; buf[i]=0;
return i;
}
if (d < 0.0) { d=-d; *buf='-'; --maxlen; ++buf; }
/*
Perform rounding. It needs to be done before we generate any
digits as the carry could propagate through the whole number.
*/
tmp = 0.5;
for (i = 0; i < prec2; i++) { tmp *= 0.1; }
d += tmp;
if (d < 1.0) { *buf='0'; --maxlen; ++buf; }
/* printf("e=%d e10=%d prec=%d\n",e,e10,prec); */
if (e10>0) {
int first=1; /* are we about to write the first digit? */
tmp = 10.0;
i=e10;
while (i>10) { tmp=tmp*1e10; i-=10; }
while (i>1) { tmp=tmp*10; --i; }
/* the number is greater than 1. Iterate through digits before the
* decimal point until we reach the decimal point or maxlen is
* reached (in which case we switch to scientific notation). */
while (tmp>0.9) {
char digit;
double fraction=d/tmp;
digit=(int)(fraction); /* floor() */
if (!first || digit) {
first=0;
*buf=digit+'0'; ++buf;
if (!maxlen) {
/* use scientific notation */
int len=__dtostr(backup/tmp,oldbuf,maxlen,prec,prec2,0);
int initial=1;
if (len==0) return 0;
maxlen-=len; buf+=len;
if (maxlen>0) {
*buf='e';
++buf;
}
--maxlen;
for (len=1000; len>0; len/=10) {
if (e10>=len || !initial) {
if (maxlen>0) {
*buf=(e10/len)+'0';
++buf;
}
--maxlen;
initial=0;
e10=e10%len;
}
}
if (maxlen>0) goto fini;
return 0;
}
d-=digit*tmp;
--maxlen;
}
tmp/=10.0;
}
}
else
{
tmp = 0.1;
}
if (buf==oldbuf) {
if (!maxlen) return 0;
--maxlen;
*buf='0'; ++buf;
}
if (prec2 || prec>(unsigned int)(buf-oldbuf)+1) { /* more digits wanted */
if (!maxlen) return 0;
--maxlen;
*buf='.'; ++buf;
if ((flags & 0x01)) {
if (prec2) prec=prec2;
prec-=buf-oldbuf-1;
} else {
prec-=buf-oldbuf-1;
if (prec2) prec=prec2;
}
if (prec>maxlen) return 0;
while (prec>0) {
char digit;
double fraction=d/tmp;
digit=(int)(fraction); /* floor() */
*buf=digit+'0'; ++buf;
d-=digit*tmp;
tmp/=10.0;
--prec;
}
}
fini:
*buf=0;
return buf-oldbuf;
}
LinuxTV legacy CVS <linuxtv.org/cvs>