[1] | 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 | } |
---|