summaryrefslogtreecommitdiffstats
path: root/mdk-stage1/dietlibc/lib/__dtostr.c
diff options
context:
space:
mode:
Diffstat (limited to 'mdk-stage1/dietlibc/lib/__dtostr.c')
-rw-r--r--mdk-stage1/dietlibc/lib/__dtostr.c190
1 files changed, 113 insertions, 77 deletions
diff --git a/mdk-stage1/dietlibc/lib/__dtostr.c b/mdk-stage1/dietlibc/lib/__dtostr.c
index e9a8a83d3..580258936 100644
--- a/mdk-stage1/dietlibc/lib/__dtostr.c
+++ b/mdk-stage1/dietlibc/lib/__dtostr.c
@@ -1,104 +1,140 @@
-#include <stdio.h>
+#include <stdlib.h>
+#include <endian.h>
+#include <math.h>
/* convert double to string. Helper for sprintf. */
-int __dtostr(double d,char *buf,int maxlen,int prec) {
+static int copystring(char* buf,int maxlen, const char* s) {
+ int i;
+ for (i=0; i<3&&i<maxlen; ++i)
+ buf[i]=s[i];
+ if (i<maxlen) { buf[i]=0; ++i; }
+ return i;
+}
+
+int __dtostr(double d,char *buf,unsigned int maxlen,unsigned int prec,unsigned int prec2) {
+#if 1
unsigned long long *x=(unsigned long long *)&d;
/* step 1: extract sign, mantissa and exponent */
- signed int s=*x>>63;
signed long e=((*x>>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=*x & ((1ull<<52)-1); */
/* step 2: exponent is base 2, compute exponent for base 10 */
- signed long e10=1+(long)(e*0.30102999566398119802); /* log10(2) */
+ signed long e10;
/* step 3: calculate 10^e10 */
- int i;
- double tmp=10.0;
+ unsigned int i;
+ double backup=d;
+ double tmp;
char *oldbuf=buf;
- int initial=1;
+ if (isnan(d)) return copystring(buf,maxlen,"nan");
+ if ((i=isinf(d))) return copystring(buf,maxlen,i>0?"inf":"-inf");
+ 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) {
- *buf='0'; ++buf;
- goto done;
+ prec2=prec2==0?1:prec2+2;
+ prec2=prec2>maxlen?8:prec2;
+ for (i=0; i<prec2; ++i) buf[i]='0';
+ buf[1]='.'; buf[i]=0;
+ return i;
}
- if (s) { d=-d; *buf='-'; --maxlen; buf++; }
+
+ 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) {
+ 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; }
- } else {
- i=(e10=-e10);
- while (i>10) { tmp=tmp*1e-10; i-=10; }
- while (i>1) { tmp=tmp/10; --i; }
- }
- while (d/tmp<1) {
- --e10;
- tmp/=10.0;
- }
- /* step 4: see if precision is sufficient to display all digits */
- if (e10>prec) {
- /* use scientific notation */
- int len=__dtostr(d/tmp,buf,maxlen,prec);
- if (len==0) return 0;
- maxlen-=len; buf+=len;
- if (--maxlen>=0) {
- *buf='e';
- ++buf;
- }
- for (len=1000; len>0; len/=10) {
- if (e10>=len || !initial) {
- if (--maxlen>=0) {
- *buf=(e10/len)+'0';
- ++buf;
+ /* 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);
+ 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;
}
- initial=0;
- e10=e10%len;
+ d-=digit*tmp;
+ --maxlen;
}
+ tmp/=10.0;
}
- if (maxlen>=0) return buf-oldbuf;
- return 0;
}
- /* step 5: loop through the digits, inserting the decimal point when
- * appropriate */
- if (d<1.0) {
- double x=1.0;
- int first=1;
- do {
- if (--maxlen<0) return buf-oldbuf;
- *buf='0'; ++buf;
- if (first) {
- first=0;
- *buf='.'; ++buf;
- if (--maxlen<0) return buf-oldbuf;
- }
- x/=10.0;
- } while (x>d);
+ else
+ {
+ tmp = 0.1;
}
- for (; prec>0; ) {
- double tmp2=d/tmp;
- char c;
- d-=((int)tmp2*tmp);
- c=((int)tmp2);
- if ((!initial)||c) {
- if (--maxlen>=0) {
- initial=0;
- *buf=c+'0';
- ++buf;
- } else
- return 0;
+
+ 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;
+ 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;
}
- if (tmp>0.5 && tmp<1.5) {
- tmp=1e-1;
- initial=0;
- if (--maxlen>=0) {
- *buf='.';
- ++buf;
- } else
- return 0;
- } else
- tmp/=10.0;
}
-done:
+fini:
*buf=0;
return buf-oldbuf;
}