00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 module mango.format.Double;
00040
00041 private import mango.format.Int,
00042 mango.format.Number;
00043
00044 extern (C) double frexp (double, int*);
00045 extern (C) int memicmp (char*, char*, uint);
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056 class Double : Number
00057 {
00058 alias double tValue;
00059
00060
00061
00062
00063
00064 private static tValue pow10 (uint exp)
00065 in {
00066 assert (exp < 512);
00067 }
00068 body
00069 {
00070 static tValue[] Powers =
00071 [
00072 1.0e1,
00073 1.0e2,
00074 1.0e4,
00075 1.0e8,
00076 1.0e16,
00077 1.0e32,
00078 1.0e64,
00079 1.0e128,
00080 1.0e256,
00081 ];
00082
00083 tValue mult = 1.0;
00084 foreach (tValue power; Powers)
00085 {
00086 if (exp & 1)
00087 mult *= power;
00088 if ((exp >>= 1) == 0)
00089 break;
00090 }
00091 return mult;
00092 }
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103 final static tValue parse (tChar[] src, uint* ate=null)
00104 {
00105 char c;
00106 char* p;
00107 int exp;
00108 bool sign;
00109 tValue value = 0.0;
00110
00111
00112 c = *(p = src.ptr + trim (src, sign));
00113
00114
00115
00116 while (c >= '0' && c <= '9')
00117 {
00118 value = value * 10 + (c - '0');
00119 c = *++p;
00120 }
00121
00122
00123 if (c == '.')
00124 c = *++p;
00125
00126
00127
00128
00129
00130
00131
00132
00133 while (c >= '0' && c <= '9')
00134 {
00135 value = value * 10 + (c - '0');
00136 c = *++p;
00137 --exp;
00138 }
00139
00140
00141 if (value)
00142 {
00143
00144 if (c == 'e' || c == 'E')
00145 {
00146 uint len;
00147 exp += Int.parse (src[(p-src.ptr)+1..length], Radix.Decimal, &len);
00148 p += len;
00149 }
00150
00151
00152
00153 if (exp < 0)
00154 value /= pow10 (-exp);
00155 else
00156 value *= pow10 (exp);
00157 }
00158 else
00159
00160 if (p == src.ptr)
00161 if (memicmp (p, "inf", 3) == 0)
00162 p += 3, value = tValue.infinity;
00163 else
00164 if (memicmp (p, "nan", 3) == 0)
00165 p += 3, value = tValue.nan;
00166
00167
00168 if (ate)
00169 *ate = p - src.ptr;
00170 return sign ? -value : value;
00171 }
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186 static final tChar[] format (tChar[] dst, tValue x, uint decimals = 6, bool scientific = false)
00187 in {
00188 assert (dst.length >= 32);
00189 }
00190 body
00191 {
00192
00193
00194 static int toDigit (inout tValue v, inout int count)
00195 {
00196 int digit;
00197
00198
00199 if (++count > 17)
00200 digit = 0;
00201 else
00202 {
00203
00204 digit = cast(int) v;
00205 v = (v - digit) * 10.0;
00206 }
00207 return digit + '0';
00208 }
00209
00210
00211 if (((cast(ushort*) &x)[3] & 0x7ff0) == 0x7ff0)
00212 if (*(cast(ulong*) &x) & 0x000f_ffff_ffff_ffff)
00213 return "nan";
00214 else
00215 return "inf";
00216
00217 int exp;
00218 bool sign;
00219
00220
00221 if (x < 0.0)
00222 {
00223 x = -x;
00224 sign = true;
00225 }
00226
00227
00228 if (x > 0.0)
00229 {
00230
00231 x += 0.5 / pow10 (decimals);
00232
00233
00234 frexp (x, &exp);
00235 exp = cast(int) (0.301029995664 * exp);
00236
00237
00238 int len = exp;
00239 if (exp < 0)
00240 {
00241 --exp;
00242 x *= pow10 (len = -exp);
00243 }
00244 else
00245 x /= pow10 (exp);
00246
00247
00248 if (len + 32 > dst.length)
00249 scientific = true;
00250 }
00251
00252 char*p = dst;
00253 int count = 0;
00254
00255
00256 if (sign)
00257 *p++ = '-';
00258
00259
00260 if (scientific)
00261 {
00262
00263 *p++ = toDigit (x, count);
00264 *p++ = '.';
00265
00266
00267 while (decimals-- > 0)
00268 *p++ = toDigit (x, count);
00269
00270
00271 if (exp)
00272 {
00273 *p++ = 'e';
00274 *p++ = (exp < 0) ? '-' : '+';
00275 if (exp < 0)
00276 exp = -exp;
00277
00278 if (exp >= 100)
00279 {
00280 *p++ = (exp/100) + '0';
00281 exp %= 100;
00282 }
00283
00284 *p++ = (exp/10) + '0';
00285 *p++ = (exp%10) + '0';
00286 }
00287 }
00288 else
00289 {
00290
00291 if (exp < 0)
00292 *p++ = '0';
00293 else
00294
00295 for (; exp >= 0; --exp)
00296 *p++ = toDigit (x, count);
00297
00298
00299 *p++ = '.';
00300
00301
00302 for (++exp; exp < 0 && decimals > 0; --decimals, ++exp)
00303 *p++ = '0';
00304
00305
00306
00307 while (decimals-- > 0)
00308 *p++ = toDigit (x, count);
00309 }
00310
00311 return dst [0..(p - dst.ptr)];
00312 }
00313
00314
00315 /+
00316
00317
00318
00319
00320
00321
00322 version (ReadLimit)
00323 {
00324 int len;
00325 const int MaxDigits = 17;
00326
00327 p = d.ptr + trimZero (d) - 1;
00328
00329 while ((c = *++p) >= '0' && c <= '9')
00330 {
00331 if (++len < MaxDigits)
00332 value = value * 10 + (c - '0');
00333 else
00334
00335 ++exp;
00336 }
00337
00338 if (c == '.')
00339 {
00340
00341
00342 if (value == 0)
00343 {
00344 while (*++p == '0')
00345 --exp;
00346 --p;
00347 }
00348
00349 while ((c = *++p) >= '0' && c <= '9')
00350 {
00351 if (++len < MaxDigits)
00352 {
00353 --exp;
00354 value = value * 10 + (c - '0');
00355 }
00356 }
00357 }
00358
00359 if (len == 0)
00360 {
00361 if (c != '0' && d.length >= 3)
00362 if (d == "inf")
00363 return tValue.infinity;
00364 else
00365 if (d == "nan")
00366 return tValue.nan;
00367 return 0.0 * sign;
00368 }
00369
00370 if (c == 'e' || c == 'E')
00371 exp += strtoi (d[(p-d.ptr)+1..length]);
00372 }
00373 +/
00374 }
00375
00376