1 | #include <stdlib.h> |
---|
2 | #include <endian.h> |
---|
3 | #include <math.h> |
---|
4 | /* convert double to string. Helper for sprintf. */ |
---|
5 | |
---|
6 | static int copystring(char* buf,int maxlen, const char* s) { |
---|
7 | int i; |
---|
8 | for (i=0; i<3&&i<maxlen; ++i) |
---|
9 | buf[i]=s[i]; |
---|
10 | if (i<maxlen) { buf[i]=0; ++i; } |
---|
11 | return i; |
---|
12 | } |
---|
13 | |
---|
14 | int __dtostr(double d,char *buf,unsigned int maxlen,unsigned int prec,unsigned int prec2,int g) { |
---|
15 | |
---|
16 | union { |
---|
17 | unsigned long long l; |
---|
18 | double d; |
---|
19 | } u = { .d=d }; |
---|
20 | #if 1 |
---|
21 | /* step 1: extract sign, mantissa and exponent */ |
---|
22 | signed long e=((u.l>>52)&((1<<11)-1))-1023; |
---|
23 | #else |
---|
24 | #if __BYTE_ORDER == __LITTLE_ENDIAN |
---|
25 | signed long e=(((((unsigned long*)&d)[1])>>20)&((1<<11)-1))-1023; |
---|
26 | #else |
---|
27 | signed long e=(((*((unsigned long*)&d))>>20)&((1<<11)-1))-1023; |
---|
28 | #endif |
---|
29 | #endif |
---|
30 | /* unsigned long long m=u.l & ((1ull<<52)-1); */ |
---|
31 | /* step 2: exponent is base 2, compute exponent for base 10 */ |
---|
32 | signed long e10; |
---|
33 | /* step 3: calculate 10^e10 */ |
---|
34 | unsigned int i; |
---|
35 | double backup=d; |
---|
36 | double tmp; |
---|
37 | char *oldbuf=buf; |
---|
38 | |
---|
39 | if ((i=isinf(d))) return copystring(buf,maxlen,i>0?"inf":"-inf"); |
---|
40 | if (isnan(d)) return copystring(buf,maxlen,"nan"); |
---|
41 | e10=1+(long)(e*0.30102999566398119802); /* log10(2) */ |
---|
42 | /* Wir iterieren von Links bis wir bei 0 sind oder maxlen erreicht |
---|
43 | * ist. Wenn maxlen erreicht ist, machen wir das nochmal in |
---|
44 | * scientific notation. Wenn dann von prec noch was übrig ist, geben |
---|
45 | * wir einen Dezimalpunkt aus und geben prec2 Nachkommastellen aus. |
---|
46 | * Wenn prec2 Null ist, geben wir so viel Stellen aus, wie von prec |
---|
47 | * noch übrig ist. */ |
---|
48 | if (d==0.0) { |
---|
49 | prec2=prec2==0?1:prec2+2; |
---|
50 | prec2=prec2>maxlen?8:prec2; |
---|
51 | i=0; |
---|
52 | if (prec2 && (long long)u.l<0) { buf[0]='-'; ++i; } |
---|
53 | for (; i<prec2; ++i) buf[i]='0'; |
---|
54 | buf[buf[0]=='0'?1:2]='.'; buf[i]=0; |
---|
55 | return i; |
---|
56 | } |
---|
57 | |
---|
58 | if (d < 0.0) { d=-d; *buf='-'; --maxlen; ++buf; } |
---|
59 | |
---|
60 | /* |
---|
61 | Perform rounding. It needs to be done before we generate any |
---|
62 | digits as the carry could propagate through the whole number. |
---|
63 | */ |
---|
64 | |
---|
65 | tmp = 0.5; |
---|
66 | for (i = 0; i < prec2; i++) { tmp *= 0.1; } |
---|
67 | d += tmp; |
---|
68 | |
---|
69 | if (d < 1.0) { *buf='0'; --maxlen; ++buf; } |
---|
70 | /* printf("e=%d e10=%d prec=%d\n",e,e10,prec); */ |
---|
71 | if (e10>0) { |
---|
72 | int first=1; /* are we about to write the first digit? */ |
---|
73 | tmp = 10.0; |
---|
74 | i=e10; |
---|
75 | while (i>10) { tmp=tmp*1e10; i-=10; } |
---|
76 | while (i>1) { tmp=tmp*10; --i; } |
---|
77 | /* the number is greater than 1. Iterate through digits before the |
---|
78 | * decimal point until we reach the decimal point or maxlen is |
---|
79 | * reached (in which case we switch to scientific notation). */ |
---|
80 | while (tmp>0.9) { |
---|
81 | char digit; |
---|
82 | double fraction=d/tmp; |
---|
83 | digit=(int)(fraction); /* floor() */ |
---|
84 | if (!first || digit) { |
---|
85 | first=0; |
---|
86 | *buf=digit+'0'; ++buf; |
---|
87 | if (!maxlen) { |
---|
88 | /* use scientific notation */ |
---|
89 | int len=__dtostr(backup/tmp,oldbuf,maxlen,prec,prec2,0); |
---|
90 | int initial=1; |
---|
91 | if (len==0) return 0; |
---|
92 | maxlen-=len; buf+=len; |
---|
93 | if (maxlen>0) { |
---|
94 | *buf='e'; |
---|
95 | ++buf; |
---|
96 | } |
---|
97 | --maxlen; |
---|
98 | for (len=1000; len>0; len/=10) { |
---|
99 | if (e10>=len || !initial) { |
---|
100 | if (maxlen>0) { |
---|
101 | *buf=(e10/len)+'0'; |
---|
102 | ++buf; |
---|
103 | } |
---|
104 | --maxlen; |
---|
105 | initial=0; |
---|
106 | e10=e10%len; |
---|
107 | } |
---|
108 | } |
---|
109 | if (maxlen>0) goto fini; |
---|
110 | return 0; |
---|
111 | } |
---|
112 | d-=digit*tmp; |
---|
113 | --maxlen; |
---|
114 | } |
---|
115 | tmp/=10.0; |
---|
116 | } |
---|
117 | } |
---|
118 | else |
---|
119 | { |
---|
120 | tmp = 0.1; |
---|
121 | } |
---|
122 | |
---|
123 | if (buf==oldbuf) { |
---|
124 | if (!maxlen) return 0; --maxlen; |
---|
125 | *buf='0'; ++buf; |
---|
126 | } |
---|
127 | if (prec2 || prec>(unsigned int)(buf-oldbuf)+1) { /* more digits wanted */ |
---|
128 | if (!maxlen) return 0; --maxlen; |
---|
129 | *buf='.'; ++buf; |
---|
130 | if (g) { |
---|
131 | if (prec2) prec=prec2; |
---|
132 | prec-=buf-oldbuf-1; |
---|
133 | } else { |
---|
134 | prec-=buf-oldbuf-1; |
---|
135 | if (prec2) prec=prec2; |
---|
136 | } |
---|
137 | if (prec>maxlen) return 0; |
---|
138 | while (prec>0) { |
---|
139 | char digit; |
---|
140 | double fraction=d/tmp; |
---|
141 | digit=(int)(fraction); /* floor() */ |
---|
142 | *buf=digit+'0'; ++buf; |
---|
143 | d-=digit*tmp; |
---|
144 | tmp/=10.0; |
---|
145 | --prec; |
---|
146 | } |
---|
147 | } |
---|
148 | fini: |
---|
149 | *buf=0; |
---|
150 | return buf-oldbuf; |
---|
151 | } |
---|