1 // Written in the D programming language.
2 
3 /*
4    Helper functions for formatting floating point numbers.
5 
6    Copyright: Copyright The D Language Foundation 2019 -
7 
8    License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
9 
10    Authors: Bernhard Seckinger
11 
12    Source: $(PHOBOSSRC std/format/internal/floats.d)
13  */
14 
15 module std.format.internal.floats;
16 
17 import std.format.spec : FormatSpec;
18 
19 // wrapper for unittests
20 private auto printFloat(T, Char)(const(T) val, FormatSpec!Char f)
21 if (is(T == float) || is(T == double)
22     || (is(T == real) && (T.mant_dig == double.mant_dig || T.mant_dig == 64)))
23 {
24     import std.array : appender;
25     auto w = appender!string();
26 
27     printFloat(w, val, f);
28     return w.data;
29 }
30 
31 package(std.format) void printFloat(Writer, T, Char)(auto ref Writer w, const(T) val, FormatSpec!Char f)
32 if (is(T == float) || is(T == double)
33     || (is(T == real) && (T.mant_dig == double.mant_dig || T.mant_dig == 64)))
34 {
35     import std.math.operations : extractBitpattern, FloatingPointBitpattern;
36 
37     auto bp = extractBitpattern(val);
38 
39     ulong mnt = bp.mantissa;
40     int exp = bp.exponent;
41     string sgn = bp.negative ? "-" : "";
42 
43     if (sgn == "" && f.flPlus) sgn = "+";
44     if (sgn == "" && f.flSpace) sgn = " ";
45 
46     assert(f.spec == 'a' || f.spec == 'A'
47            || f.spec == 'e' || f.spec == 'E'
48            || f.spec == 'f' || f.spec == 'F'
49            || f.spec == 'g' || f.spec == 'G', "unsupported format specifier");
50     bool is_upper = f.spec == 'A' || f.spec == 'E' || f.spec=='F' || f.spec=='G';
51 
52     // special treatment for nan and inf
53     if (exp == T.max_exp)
54     {
55         import std.format.internal.write : writeAligned;
56 
57         f.flZero = false;
58         writeAligned(w, sgn, "", (mnt == 0) ? ( is_upper ? "INF" : "inf" ) : ( is_upper ? "NAN" : "nan" ), f);
59         return;
60     }
61 
62     final switch (f.spec)
63     {
64         case 'a': case 'A':
65             printFloatA(w, val, f, sgn, exp, mnt, is_upper);
66             break;
67         case 'e': case 'E':
68             printFloatE!false(w, val, f, sgn, exp, mnt, is_upper);
69             break;
70         case 'f': case 'F':
71             printFloatF!false(w, val, f, sgn, exp, mnt, is_upper);
72             break;
73         case 'g': case 'G':
74             printFloatG(w, val, f, sgn, exp, mnt, is_upper);
75             break;
76     }
77 }
78 
79 private void printFloatA(Writer, T, Char)(auto ref Writer w, const(T) val,
80     FormatSpec!Char f, string sgn, int exp, ulong mnt, bool is_upper)
81 if (is(T == float) || is(T == double)
82     || (is(T == real) && (T.mant_dig == double.mant_dig || T.mant_dig == 64)))
83 {
84     import std.algorithm.comparison : max;
85     import std.format.internal.write : writeAligned, PrecisionType;
86 
87     char[3] prefix;
88     if (sgn != "") prefix[0] = sgn[0];
89     prefix[1] = '0';
90     prefix[2] = is_upper ? 'X' : 'x';
91 
92     // print exponent
93     if (mnt == 0)
94     {
95         if (f.precision == f.UNSPECIFIED)
96             f.precision = 0;
97         writeAligned(w, prefix[1 - sgn.length .. $], "0", ".", is_upper ? "P+0" : "p+0",
98                      f, PrecisionType.fractionalDigits);
99         return;
100     }
101 
102     // save integer part
103     char first = '0' + ((mnt >> (T.mant_dig - 1)) & 1);
104     mnt &= (1L << (T.mant_dig - 1)) - 1;
105 
106     static if (is(T == float) || (is(T == real) && T.mant_dig == 64))
107     {
108         mnt <<= 1; // make mnt dividable by 4
109         enum mant_len = T.mant_dig;
110     }
111     else
112         enum mant_len = T.mant_dig - 1;
113     static assert(mant_len % 4 == 0, "mantissa with wrong length");
114 
115     // print full mantissa
116     char[(mant_len - 1) / 4 + 3] hex_mant;
117     size_t hex_mant_pos = 2;
118     size_t pos = mant_len;
119 
120     auto gap = 39 - 32 * is_upper;
121     while (pos >= 4 && (mnt & (((1L << (pos - 1)) - 1) << 1) + 1) != 0)
122     {
123         pos -= 4;
124         size_t tmp = (mnt >> pos) & 15;
125         // For speed reasons the better readable
126         // ... = tmp < 10 ? ('0' + tmp) : ((is_upper ? 'A' : 'a') + tmp - 10))
127         // has been replaced with an expression without branches, doing the same
128         hex_mant[hex_mant_pos++] = cast(char) (tmp + gap * ((tmp + 6) >> 4) + '0');
129     }
130     hex_mant[0] = first;
131     hex_mant[1] = '.';
132 
133     if (f.precision == f.UNSPECIFIED)
134         f.precision = cast(int) hex_mant_pos - 2;
135 
136     auto exp_sgn = exp >= 0 ? '+' : '-';
137     if (exp < 0) exp = -exp;
138 
139     static if (is(T == real) && real.mant_dig == 64)
140         enum max_exp_digits = 8;
141     else static if (is(T == float))
142         enum max_exp_digits = 5;
143     else
144         enum max_exp_digits = 6;
145 
146     char[max_exp_digits] exp_str;
147     size_t exp_pos = max_exp_digits;
148 
149     do
150     {
151         exp_str[--exp_pos] = '0' + exp % 10;
152         exp /= 10;
153     } while (exp > 0);
154 
155     exp_str[--exp_pos] = exp_sgn;
156     exp_str[--exp_pos] = is_upper ? 'P' : 'p';
157 
158     if (f.precision < hex_mant_pos - 2)
159     {
160         import std.format.internal.write : RoundingClass, round;
161 
162         RoundingClass rc;
163 
164         if (hex_mant[f.precision + 2] == '0')
165             rc = RoundingClass.ZERO;
166         else if (hex_mant[f.precision + 2] < '8')
167             rc = RoundingClass.LOWER;
168         else if (hex_mant[f.precision + 2] > '8')
169             rc = RoundingClass.UPPER;
170         else
171             rc = RoundingClass.FIVE;
172 
173         if (rc == RoundingClass.ZERO || rc == RoundingClass.FIVE)
174         {
175             foreach (i;f.precision + 3 .. hex_mant_pos)
176             {
177                 if (hex_mant[i] > '0')
178                 {
179                     rc = rc == RoundingClass.ZERO ? RoundingClass.LOWER : RoundingClass.UPPER;
180                     break;
181                 }
182             }
183         }
184 
185         hex_mant_pos = f.precision + 2;
186 
187         round(hex_mant, 0, hex_mant_pos, rc, sgn == "-", is_upper ? 'F' : 'f');
188     }
189 
190     writeAligned(w, prefix[1 - sgn.length .. $], hex_mant[0 .. 1], hex_mant[1 .. hex_mant_pos],
191                  exp_str[exp_pos .. $], f, PrecisionType.fractionalDigits);
192 }
193 
194 @safe unittest
195 {
196     auto f = FormatSpec!dchar("");
197     f.spec = 'a';
198     assert(printFloat(float.nan, f) == "nan");
199     assert(printFloat(-float.nan, f) == "-nan");
200     assert(printFloat(float.infinity, f) == "inf");
201     assert(printFloat(-float.infinity, f) == "-inf");
202     assert(printFloat(0.0f, f) == "0x0p+0");
203     assert(printFloat(-0.0f, f) == "-0x0p+0");
204 
205     assert(printFloat(double.nan, f) == "nan");
206     assert(printFloat(-double.nan, f) == "-nan");
207     assert(printFloat(double.infinity, f) == "inf");
208     assert(printFloat(-double.infinity, f) == "-inf");
209     assert(printFloat(0.0, f) == "0x0p+0");
210     assert(printFloat(-0.0, f) == "-0x0p+0");
211 
212     static if (real.mant_dig > 64)
213     {
214         pragma(msg, "printFloat tests disabled because of unsupported `real` format");
215     }
216     else
217     {
218         assert(printFloat(real.nan, f) == "nan");
219         assert(printFloat(-real.nan, f) == "-nan");
220         assert(printFloat(real.infinity, f) == "inf");
221         assert(printFloat(-real.infinity, f) == "-inf");
222         assert(printFloat(0.0L, f) == "0x0p+0");
223         assert(printFloat(-0.0L, f) == "-0x0p+0");
224     }
225 
226     import std.math.operations : nextUp;
227 
228     assert(printFloat(nextUp(0.0f), f) == "0x0.000002p-126");
229     assert(printFloat(float.epsilon, f) == "0x1p-23");
230     assert(printFloat(float.min_normal, f) == "0x1p-126");
231     assert(printFloat(float.max, f) == "0x1.fffffep+127");
232 
233     assert(printFloat(nextUp(0.0), f) == "0x0.0000000000001p-1022");
234     assert(printFloat(double.epsilon, f) == "0x1p-52");
235     assert(printFloat(double.min_normal, f) == "0x1p-1022");
236     assert(printFloat(double.max, f) == "0x1.fffffffffffffp+1023");
237 
238     static if (real.mant_dig == 64)
239     {
240         assert(printFloat(nextUp(0.0L), f) == "0x0.0000000000000002p-16382");
241         assert(printFloat(real.epsilon, f) == "0x1p-63");
242         assert(printFloat(real.min_normal, f) == "0x1p-16382");
243         assert(printFloat(real.max, f) == "0x1.fffffffffffffffep+16383");
244     }
245 
246     import std.math.constants : E, PI, PI_2, PI_4, M_1_PI, M_2_PI, M_2_SQRTPI,
247                                 LN10, LN2, LOG2, LOG2E, LOG2T, LOG10E, SQRT2, SQRT1_2;
248 
249     assert(printFloat(cast(float) E, f) == "0x1.5bf0a8p+1");
250     assert(printFloat(cast(float) PI, f) == "0x1.921fb6p+1");
251     assert(printFloat(cast(float) PI_2, f) == "0x1.921fb6p+0");
252     assert(printFloat(cast(float) PI_4, f) == "0x1.921fb6p-1");
253     assert(printFloat(cast(float) M_1_PI, f) == "0x1.45f306p-2");
254     assert(printFloat(cast(float) M_2_PI, f) == "0x1.45f306p-1");
255     assert(printFloat(cast(float) M_2_SQRTPI, f) == "0x1.20dd76p+0");
256     assert(printFloat(cast(float) LN10, f) == "0x1.26bb1cp+1");
257     assert(printFloat(cast(float) LN2, f) == "0x1.62e43p-1");
258     assert(printFloat(cast(float) LOG2, f) == "0x1.344136p-2");
259     assert(printFloat(cast(float) LOG2E, f) == "0x1.715476p+0");
260     assert(printFloat(cast(float) LOG2T, f) == "0x1.a934fp+1");
261     assert(printFloat(cast(float) LOG10E, f) == "0x1.bcb7b2p-2");
262     assert(printFloat(cast(float) SQRT2, f) == "0x1.6a09e6p+0");
263     assert(printFloat(cast(float) SQRT1_2, f) == "0x1.6a09e6p-1");
264 
265     assert(printFloat(cast(double) E, f) == "0x1.5bf0a8b145769p+1");
266     assert(printFloat(cast(double) PI, f) == "0x1.921fb54442d18p+1");
267     assert(printFloat(cast(double) PI_2, f) == "0x1.921fb54442d18p+0");
268     assert(printFloat(cast(double) PI_4, f) == "0x1.921fb54442d18p-1");
269     assert(printFloat(cast(double) M_1_PI, f) == "0x1.45f306dc9c883p-2");
270     assert(printFloat(cast(double) M_2_PI, f) == "0x1.45f306dc9c883p-1");
271     assert(printFloat(cast(double) M_2_SQRTPI, f) == "0x1.20dd750429b6dp+0");
272     assert(printFloat(cast(double) LN10, f) == "0x1.26bb1bbb55516p+1");
273     assert(printFloat(cast(double) LN2, f) == "0x1.62e42fefa39efp-1");
274     assert(printFloat(cast(double) LOG2, f) == "0x1.34413509f79ffp-2");
275     assert(printFloat(cast(double) LOG2E, f) == "0x1.71547652b82fep+0");
276     assert(printFloat(cast(double) LOG2T, f) == "0x1.a934f0979a371p+1");
277     assert(printFloat(cast(double) LOG10E, f) == "0x1.bcb7b1526e50ep-2");
278     assert(printFloat(cast(double) SQRT2, f) == "0x1.6a09e667f3bcdp+0");
279     assert(printFloat(cast(double) SQRT1_2, f) == "0x1.6a09e667f3bcdp-1");
280 
281     static if (real.mant_dig == 64)
282     {
283         assert(printFloat(E, f) == "0x1.5bf0a8b145769536p+1");
284         assert(printFloat(PI, f) == "0x1.921fb54442d1846ap+1");
285         assert(printFloat(PI_2, f) == "0x1.921fb54442d1846ap+0");
286         assert(printFloat(PI_4, f) == "0x1.921fb54442d1846ap-1");
287         assert(printFloat(M_1_PI, f) == "0x1.45f306dc9c882a54p-2");
288         assert(printFloat(M_2_PI, f) == "0x1.45f306dc9c882a54p-1");
289         assert(printFloat(M_2_SQRTPI, f) == "0x1.20dd750429b6d11ap+0");
290         assert(printFloat(LN10, f) == "0x1.26bb1bbb5551582ep+1");
291         assert(printFloat(LN2, f) == "0x1.62e42fefa39ef358p-1");
292         assert(printFloat(LOG2, f) == "0x1.34413509f79fef32p-2");
293         assert(printFloat(LOG2E, f) == "0x1.71547652b82fe178p+0");
294         assert(printFloat(LOG2T, f) == "0x1.a934f0979a3715fcp+1");
295         assert(printFloat(LOG10E, f) == "0x1.bcb7b1526e50e32ap-2");
296         assert(printFloat(SQRT2, f) == "0x1.6a09e667f3bcc908p+0");
297         assert(printFloat(SQRT1_2, f) == "0x1.6a09e667f3bcc908p-1");
298     }
299 }
300 
301 @safe unittest
302 {
303     auto f = FormatSpec!dchar("");
304     f.spec = 'a';
305     f.precision = 3;
306 
307     assert(printFloat(1.0f, f) == "0x1.000p+0");
308     assert(printFloat(3.3f, f) == "0x1.a66p+1");
309     assert(printFloat(2.9f, f) == "0x1.733p+1");
310 
311     assert(printFloat(1.0, f) == "0x1.000p+0");
312     assert(printFloat(3.3, f) == "0x1.a66p+1");
313     assert(printFloat(2.9, f) == "0x1.733p+1");
314 
315     static if (real.mant_dig == 64)
316     {
317         assert(printFloat(1.0L, f) == "0x1.000p+0");
318         assert(printFloat(3.3L, f) == "0x1.a66p+1");
319         assert(printFloat(2.9L, f) == "0x1.733p+1");
320     }
321 }
322 
323 @safe unittest
324 {
325     auto f = FormatSpec!dchar("");
326     f.spec = 'a';
327     f.precision = 0;
328 
329     assert(printFloat(1.0f, f) == "0x1p+0");
330     assert(printFloat(3.3f, f) == "0x2p+1");
331     assert(printFloat(2.9f, f) == "0x1p+1");
332 
333     assert(printFloat(1.0, f) == "0x1p+0");
334     assert(printFloat(3.3, f) == "0x2p+1");
335     assert(printFloat(2.9, f) == "0x1p+1");
336 
337     static if (real.mant_dig == 64)
338     {
339         assert(printFloat(1.0L, f) == "0x1p+0");
340         assert(printFloat(3.3L, f) == "0x2p+1");
341         assert(printFloat(2.9L, f) == "0x1p+1");
342     }
343 }
344 
345 @safe unittest
346 {
347     auto f = FormatSpec!dchar("");
348     f.spec = 'a';
349     f.precision = 0;
350     f.flHash = true;
351 
352     assert(printFloat(1.0f, f) == "0x1.p+0");
353     assert(printFloat(3.3f, f) == "0x2.p+1");
354     assert(printFloat(2.9f, f) == "0x1.p+1");
355 
356     assert(printFloat(1.0, f) == "0x1.p+0");
357     assert(printFloat(3.3, f) == "0x2.p+1");
358     assert(printFloat(2.9, f) == "0x1.p+1");
359 
360     static if (real.mant_dig == 64)
361     {
362         assert(printFloat(1.0L, f) == "0x1.p+0");
363         assert(printFloat(3.3L, f) == "0x2.p+1");
364         assert(printFloat(2.9L, f) == "0x1.p+1");
365     }
366 }
367 
368 @safe unittest
369 {
370     auto f = FormatSpec!dchar("");
371     f.spec = 'a';
372     f.width = 22;
373 
374     assert(printFloat(1.0f, f) == "                0x1p+0");
375     assert(printFloat(3.3f, f) == "         0x1.a66666p+1");
376     assert(printFloat(2.9f, f) == "         0x1.733334p+1");
377 
378     assert(printFloat(1.0, f) == "                0x1p+0");
379     assert(printFloat(3.3, f) == "  0x1.a666666666666p+1");
380     assert(printFloat(2.9, f) == "  0x1.7333333333333p+1");
381 
382     static if (real.mant_dig == 64)
383     {
384         f.width = 25;
385         assert(printFloat(1.0L, f) == "                   0x1p+0");
386         assert(printFloat(3.3L, f) == "  0x1.a666666666666666p+1");
387         assert(printFloat(2.9L, f) == "  0x1.7333333333333334p+1");
388     }
389 }
390 
391 @safe unittest
392 {
393     auto f = FormatSpec!dchar("");
394     f.spec = 'a';
395     f.width = 22;
396     f.flDash = true;
397 
398     assert(printFloat(1.0f, f) == "0x1p+0                ");
399     assert(printFloat(3.3f, f) == "0x1.a66666p+1         ");
400     assert(printFloat(2.9f, f) == "0x1.733334p+1         ");
401 
402     assert(printFloat(1.0, f) == "0x1p+0                ");
403     assert(printFloat(3.3, f) == "0x1.a666666666666p+1  ");
404     assert(printFloat(2.9, f) == "0x1.7333333333333p+1  ");
405 
406     static if (real.mant_dig == 64)
407     {
408         f.width = 25;
409         assert(printFloat(1.0L, f) == "0x1p+0                   ");
410         assert(printFloat(3.3L, f) == "0x1.a666666666666666p+1  ");
411         assert(printFloat(2.9L, f) == "0x1.7333333333333334p+1  ");
412     }
413 }
414 
415 @safe unittest
416 {
417     auto f = FormatSpec!dchar("");
418     f.spec = 'a';
419     f.width = 22;
420     f.flZero = true;
421 
422     assert(printFloat(1.0f, f) == "0x00000000000000001p+0");
423     assert(printFloat(3.3f, f) == "0x0000000001.a66666p+1");
424     assert(printFloat(2.9f, f) == "0x0000000001.733334p+1");
425 
426     assert(printFloat(1.0, f) == "0x00000000000000001p+0");
427     assert(printFloat(3.3, f) == "0x001.a666666666666p+1");
428     assert(printFloat(2.9, f) == "0x001.7333333333333p+1");
429 
430     static if (real.mant_dig == 64)
431     {
432         f.width = 25;
433         assert(printFloat(1.0L, f) == "0x00000000000000000001p+0");
434         assert(printFloat(3.3L, f) == "0x001.a666666666666666p+1");
435         assert(printFloat(2.9L, f) == "0x001.7333333333333334p+1");
436     }
437 }
438 
439 @safe unittest
440 {
441     auto f = FormatSpec!dchar("");
442     f.spec = 'a';
443     f.width = 22;
444     f.flPlus = true;
445 
446     assert(printFloat(1.0f, f) == "               +0x1p+0");
447     assert(printFloat(3.3f, f) == "        +0x1.a66666p+1");
448     assert(printFloat(2.9f, f) == "        +0x1.733334p+1");
449 
450     assert(printFloat(1.0, f) == "               +0x1p+0");
451     assert(printFloat(3.3, f) == " +0x1.a666666666666p+1");
452     assert(printFloat(2.9, f) == " +0x1.7333333333333p+1");
453 
454     static if (real.mant_dig == 64)
455     {
456         f.width = 25;
457         assert(printFloat(1.0L, f) == "                  +0x1p+0");
458         assert(printFloat(3.3L, f) == " +0x1.a666666666666666p+1");
459         assert(printFloat(2.9L, f) == " +0x1.7333333333333334p+1");
460     }
461 }
462 
463 @safe unittest
464 {
465     auto f = FormatSpec!dchar("");
466     f.spec = 'a';
467     f.width = 22;
468     f.flDash = true;
469     f.flSpace = true;
470 
471     assert(printFloat(1.0f, f) == " 0x1p+0               ");
472     assert(printFloat(3.3f, f) == " 0x1.a66666p+1        ");
473     assert(printFloat(2.9f, f) == " 0x1.733334p+1        ");
474 
475     assert(printFloat(1.0, f) == " 0x1p+0               ");
476     assert(printFloat(3.3, f) == " 0x1.a666666666666p+1 ");
477     assert(printFloat(2.9, f) == " 0x1.7333333333333p+1 ");
478 
479     static if (real.mant_dig == 64)
480     {
481         f.width = 25;
482         assert(printFloat(1.0L, f) == " 0x1p+0                  ");
483         assert(printFloat(3.3L, f) == " 0x1.a666666666666666p+1 ");
484         assert(printFloat(2.9L, f) == " 0x1.7333333333333334p+1 ");
485     }
486 }
487 
488 @safe unittest
489 {
490     import std.math.hardware; // cannot be selective, because FloatingPointControl might not be defined
491 
492     // std.math's FloatingPointControl isn't available on all target platforms
493     static if (is(FloatingPointControl))
494     {
495         FloatingPointControl fpctrl;
496 
497         auto f = FormatSpec!dchar("");
498         f.spec = 'a';
499         f.precision = 1;
500 
501         fpctrl.rounding = FloatingPointControl.roundToNearest;
502 
503         /* tiesAwayFromZero currently not supported
504          assert(printFloat(0x1.18p0,  f) == "0x1.2p+0");
505          assert(printFloat(0x1.28p0,  f) == "0x1.3p+0");
506          assert(printFloat(0x1.1ap0,  f) == "0x1.2p+0");
507          assert(printFloat(0x1.16p0,  f) == "0x1.1p+0");
508          assert(printFloat(0x1.10p0,  f) == "0x1.1p+0");
509          assert(printFloat(-0x1.18p0, f) == "-0x1.2p+0");
510          assert(printFloat(-0x1.28p0, f) == "-0x1.3p+0");
511          assert(printFloat(-0x1.1ap0, f) == "-0x1.2p+0");
512          assert(printFloat(-0x1.16p0, f) == "-0x1.1p+0");
513          assert(printFloat(-0x1.10p0, f) == "-0x1.1p+0");
514          */
515 
516         assert(printFloat(0x1.18p0,  f) == "0x1.2p+0");
517         assert(printFloat(0x1.28p0,  f) == "0x1.2p+0");
518         assert(printFloat(0x1.1ap0,  f) == "0x1.2p+0");
519         assert(printFloat(0x1.16p0,  f) == "0x1.1p+0");
520         assert(printFloat(0x1.10p0,  f) == "0x1.1p+0");
521         assert(printFloat(-0x1.18p0, f) == "-0x1.2p+0");
522         assert(printFloat(-0x1.28p0, f) == "-0x1.2p+0");
523         assert(printFloat(-0x1.1ap0, f) == "-0x1.2p+0");
524         assert(printFloat(-0x1.16p0, f) == "-0x1.1p+0");
525         assert(printFloat(-0x1.10p0, f) == "-0x1.1p+0");
526 
527         fpctrl.rounding = FloatingPointControl.roundToZero;
528 
529         assert(printFloat(0x1.18p0,  f) == "0x1.1p+0");
530         assert(printFloat(0x1.28p0,  f) == "0x1.2p+0");
531         assert(printFloat(0x1.1ap0,  f) == "0x1.1p+0");
532         assert(printFloat(0x1.16p0,  f) == "0x1.1p+0");
533         assert(printFloat(0x1.10p0,  f) == "0x1.1p+0");
534         assert(printFloat(-0x1.18p0, f) == "-0x1.1p+0");
535         assert(printFloat(-0x1.28p0, f) == "-0x1.2p+0");
536         assert(printFloat(-0x1.1ap0, f) == "-0x1.1p+0");
537         assert(printFloat(-0x1.16p0, f) == "-0x1.1p+0");
538         assert(printFloat(-0x1.10p0, f) == "-0x1.1p+0");
539 
540         fpctrl.rounding = FloatingPointControl.roundUp;
541 
542         assert(printFloat(0x1.18p0,  f) == "0x1.2p+0");
543         assert(printFloat(0x1.28p0,  f) == "0x1.3p+0");
544         assert(printFloat(0x1.1ap0,  f) == "0x1.2p+0");
545         assert(printFloat(0x1.16p0,  f) == "0x1.2p+0");
546         assert(printFloat(0x1.10p0,  f) == "0x1.1p+0");
547         assert(printFloat(-0x1.18p0, f) == "-0x1.1p+0");
548         assert(printFloat(-0x1.28p0, f) == "-0x1.2p+0");
549         assert(printFloat(-0x1.1ap0, f) == "-0x1.1p+0");
550         assert(printFloat(-0x1.16p0, f) == "-0x1.1p+0");
551         assert(printFloat(-0x1.10p0, f) == "-0x1.1p+0");
552 
553         fpctrl.rounding = FloatingPointControl.roundDown;
554 
555         assert(printFloat(0x1.18p0,  f) == "0x1.1p+0");
556         assert(printFloat(0x1.28p0,  f) == "0x1.2p+0");
557         assert(printFloat(0x1.1ap0,  f) == "0x1.1p+0");
558         assert(printFloat(0x1.16p0,  f) == "0x1.1p+0");
559         assert(printFloat(0x1.10p0,  f) == "0x1.1p+0");
560         assert(printFloat(-0x1.18p0, f) == "-0x1.2p+0");
561         assert(printFloat(-0x1.28p0, f) == "-0x1.3p+0");
562         assert(printFloat(-0x1.1ap0, f) == "-0x1.2p+0");
563         assert(printFloat(-0x1.16p0, f) == "-0x1.2p+0");
564         assert(printFloat(-0x1.10p0, f) == "-0x1.1p+0");
565     }
566 }
567 
568 // for 100% coverage
569 @safe unittest
570 {
571     auto f = FormatSpec!dchar("");
572     f.spec = 'a';
573     f.precision = 3;
574 
575     assert(printFloat(0x1.19f81p0, f) == "0x1.1a0p+0");
576     assert(printFloat(0x1.19f01p0, f) == "0x1.19fp+0");
577 }
578 
579 @safe unittest
580 {
581     auto f = FormatSpec!dchar("");
582     f.spec = 'A';
583     f.precision = 3;
584 
585     assert(printFloat(0x1.19f81p0, f) == "0X1.1A0P+0");
586     assert(printFloat(0x1.19f01p0, f) == "0X1.19FP+0");
587 }
588 
589 private void printFloatE(bool g, Writer, T, Char)(auto ref Writer w, const(T) val,
590     FormatSpec!Char f, string sgn, int exp, ulong mnt, bool is_upper)
591 if (is(T == float) || is(T == double)
592     || (is(T == real) && (T.mant_dig == double.mant_dig || T.mant_dig == 64)))
593 {
594     import std.format.internal.write : writeAligned, PrecisionType, RoundingClass, round;
595 
596     static if (!g)
597     {
598         if (f.precision == f.UNSPECIFIED)
599             f.precision = 6;
600     }
601 
602     // special treatment for 0.0
603     if (mnt == 0)
604     {
605         static if (g)
606             writeAligned(w, sgn, "0", ".", "", f, PrecisionType.allDigits);
607         else
608             writeAligned(w, sgn, "0", ".", is_upper ? "E+00" : "e+00", f, PrecisionType.fractionalDigits);
609         return;
610     }
611 
612     char[T.mant_dig + T.max_exp] dec_buf;
613     char[T.max_10_exp.stringof.length + 2] exp_buf;
614 
615     int final_exp = 0;
616 
617     RoundingClass rc;
618 
619     // Depending on exp, we will use one of three algorithms:
620     //
621     // Algorithm A: For large exponents (exp >= T.mant_dig)
622     // Algorithm B: For small exponents (exp < T.mant_dig - 61)
623     // Algorithm C: For exponents close to 0.
624     //
625     // Algorithm A:
626     //   The number to print looks like this: mantissa followed by several zeros.
627     //
628     //   We know, that there is no fractional part, so we can just use integer division,
629     //   consecutivly dividing by 10 and writing down the remainder from right to left.
630     //   Unfortunately the integer is too large to fit in an ulong, so we use something
631     //   like BigInt: An array of ulongs. We only use 60 bits of that ulongs, because
632     //   this simplifies (and speeds up) the division to come.
633     //
634     //   For the division we use integer division with reminder for each ulong and put
635     //   the reminder of each step in the first 4 bits of ulong of the next step (think of
636     //   long division for the rationale behind this). The final reminder is the next
637     //   digit (from right to left).
638     //
639     //   This results in the output we would have for the %f specifier. We now adjust this
640     //   for %e: First we calculate the place, where the exponent should be printed, filling
641     //   up with zeros if needed and second we move the leftmost digit one to the left
642     //   and inserting a dot.
643     //
644     //   After that we decide on the rounding type, using the digits right of the position,
645     //   where the exponent will be printed (currently they are still there, but will be
646     //   overwritten later).
647     //
648     // Algorithm B:
649     //   The number to print looks like this: zero dot several zeros followed by the mantissa
650     //
651     //   We know, that the number has no integer part. The algorithm consecutivly multiplies
652     //   by 10. The integer part (rounded down) after the multiplication is the next digit
653     //   (from left to right). This integer part is removed after each step.
654     //   Again, the number is represented as an array of ulongs, with only 60 bits used of
655     //   every ulong.
656     //
657     //   For the multiplication we use normal integer multiplication, which can result in digits
658     //   in the uppermost 4 bits. These 4 digits are the carry which is added to the result
659     //   of the next multiplication and finally the last carry is the next digit.
660     //
661     //   Other than for the %f specifier, this multiplication is splitted into two almost
662     //   identical parts. The first part lasts as long as we find zeros. We need to do this
663     //   to calculate the correct exponent.
664     //
665     //   The second part will stop, when only zeros remain or when we've got enough digits
666     //   for the requested precision. In the second case, we have to find out, which rounding
667     //   we have. Aside from special cases we do this by calculating one more digit.
668     //
669     // Algorithm C:
670     //   This time, we know, that the integral part and the fractional part each fit into a
671     //   ulong. The mantissa might be partially in both parts or completely in the fractional
672     //   part.
673     //
674     //   We first calculate the integral part by consecutive division by 10. Depending on the
675     //   precision this might result in more digits, than we need. In that case we calculate
676     //   the position of the exponent and the rounding type.
677     //
678     //   If there is no integral part, we need to find the first non zero digit. We do this by
679     //   consecutive multiplication by 10, saving the first non zero digit followed by a dot.
680     //
681     //   In either case, we continue filling up with the fractional part until we have enough
682     //   digits. If still necessary, we decide the rounding type, mainly by looking at the
683     //   next digit.
684 
685     size_t right = 1;
686     size_t start = 1;
687     size_t left = 1;
688 
689     static if (is(T == real) && real.mant_dig == 64)
690     {
691         enum small_bound = 0;
692         enum max_buf = 275;
693     }
694     else
695     {
696         enum small_bound = T.mant_dig - 61;
697         static if (is(T == float))
698             enum max_buf = 4;
699         else
700             enum max_buf = 18;
701     }
702 
703     ulong[max_buf] bigbuf;
704     if (exp >= T.mant_dig)
705     {
706         start = left = right = dec_buf.length;
707 
708         // large number without fractional digits
709         //
710         // As this number does not fit in a ulong, we use an array of ulongs. We only use 60 of the 64 bits,
711         // because this makes it much more easy to implement the division by 10.
712         int count = exp / 60 + 1;
713 
714         // only the first few ulongs contain the mantiassa. The rest are zeros.
715         int lower = 60 - (exp - T.mant_dig + 1) % 60;
716 
717         static if (is(T == real) && real.mant_dig == 64)
718         {
719             // for x87 reals, the lowest ulong may contain more than 60 bits,
720             // because the mantissa is 63 (>60) bits long
721             // therefore we need one ulong less
722             if (lower <= 3) count--;
723         }
724 
725         // saved in big endian format
726         ulong[] mybig = bigbuf[0 .. count];
727 
728         if (lower < T.mant_dig)
729         {
730             mybig[0] = mnt >> lower;
731             mybig[1] = (mnt & ((1L << lower) - 1)) << 60 - lower;
732         }
733         else
734             mybig[0] = (mnt & ((1L << lower) - 1)) << 60 - lower;
735 
736         // Generation of digits by consecutive division with reminder by 10.
737         int msu = 0; // Most significant ulong; when it get's zero, we can ignore it further on
738         while (msu < count - 1 || mybig[$ - 1] != 0)
739         {
740             ulong mod = 0;
foreach(i;msu..count)741             foreach (i;msu .. count)
742             {
743                 mybig[i] |= mod << 60;
744                 mod = mybig[i] % 10;
745                 mybig[i] /= 10;
746             }
747             if (mybig[msu] == 0)
748                 ++msu;
749 
750             dec_buf[--left] = cast(byte) ('0' + mod);
751             ++final_exp;
752         }
753         --final_exp;
754 
755         static if (g)
756             start = left + f.precision;
757         else
758             start = left + f.precision + 1;
759 
760         // move leftmost digit one more left and add dot between
761         dec_buf[left - 1] = dec_buf[left];
762         dec_buf[left] = '.';
763         --left;
764 
765         // rounding type
766         if (start >= right)
767             rc = RoundingClass.ZERO;
768         else if (dec_buf[start] != '0' && dec_buf[start] != '5')
769             rc = dec_buf[start] > '5' ? RoundingClass.UPPER : RoundingClass.LOWER;
770         else
771         {
772             rc = dec_buf[start] == '5' ? RoundingClass.FIVE : RoundingClass.ZERO;
773             foreach (i; start + 1 .. right)
774                 if (dec_buf[i] > '0')
775                 {
776                     rc = rc == RoundingClass.FIVE ? RoundingClass.UPPER : RoundingClass.LOWER;
777                     break;
778                 }
779         }
780 
781         if (start < right) right = start;
782     }
783     else if (exp < small_bound)
784     {
785         // small number without integer digits
786         //
787         // Again this number does not fit in a ulong and we use an array of ulongs. And again we
788         // only use 60 bits, because this simplifies the multiplication by 10.
789         int count = (T.mant_dig - exp - 2) / 60 + 1;
790 
791         // saved in little endian format
792         ulong[] mybig = bigbuf[0 .. count];
793 
794         // only the last few ulongs contain the mantiassa. Because of little endian
795         // format these are the ulongs at index 0 and 1 (and 2 in case of x87 reals).
796         // The rest are zeros.
797         int upper = 60 - (-exp - 1) % 60;
798 
799         static if (is(T == real) && real.mant_dig == 64)
800         {
801             if (upper < 4)
802             {
803                 mybig[0] = (mnt & ((1L << (4 - upper)) - 1)) << 56 + upper;
804                 mybig[1] = (mnt >> (4 - upper)) & ((1L << 60) - 1);
805                 mybig[2] = mnt >> 64 - upper;
806             }
807             else
808             {
809                 mybig[0] = (mnt & ((1L << (T.mant_dig - upper)) - 1)) << 60 - (T.mant_dig - upper);
810                 mybig[1] = mnt >> (T.mant_dig - upper);
811             }
812         }
813         else
814         {
815             if (upper < T.mant_dig)
816             {
817                 mybig[0] = (mnt & ((1L << (T.mant_dig - upper)) - 1)) << 60 - (T.mant_dig - upper);
818                 mybig[1] = mnt >> (T.mant_dig - upper);
819             }
820             else
821                 mybig[0] = mnt << (upper - T.mant_dig);
822         }
823 
824         int lsu = 0; // Least significant ulong; when it get's zero, we can ignore it further on
825 
826         // adding zeros, until we reach first nonzero
827         while (lsu < count - 1 || mybig[$ - 1]!=0)
828         {
829             ulong over = 0;
foreach(i;lsu..count)830             foreach (i; lsu .. count)
831             {
832                 mybig[i] = mybig[i] * 10 + over;
833                 over = mybig[i] >> 60;
834                 mybig[i] &= (1L << 60) - 1;
835             }
836             if (mybig[lsu] == 0)
837                 ++lsu;
838             --final_exp;
839 
840             if (over != 0)
841             {
842                 dec_buf[right++] = cast(byte) ('0' + over);
843                 dec_buf[right++] = '.';
844                 break;
845             }
846         }
847 
848         // adding more digits
849         static if (g)
850             start = right - 1;
851         else
852             start = right;
853         while ((lsu < count - 1 || mybig[$ - 1] != 0) && right - start < f.precision)
854         {
855             ulong over = 0;
foreach(i;lsu..count)856             foreach (i;lsu .. count)
857             {
858                 mybig[i] = mybig[i] * 10 + over;
859                 over = mybig[i] >> 60;
860                 mybig[i] &= (1L << 60) - 1;
861             }
862             if (mybig[lsu] == 0)
863                 ++lsu;
864 
865             dec_buf[right++] = cast(byte) ('0' + over);
866         }
867 
868         // rounding type
869         if (lsu >= count - 1 && mybig[count - 1] == 0)
870             rc = RoundingClass.ZERO;
871         else if (lsu == count - 1 && mybig[lsu] == 1L << 59)
872             rc = RoundingClass.FIVE;
873         else
874         {
875             ulong over = 0;
foreach(i;lsu..count)876             foreach (i;lsu .. count)
877             {
878                 mybig[i] = mybig[i] * 10 + over;
879                 over = mybig[i] >> 60;
880                 mybig[i] &= (1L << 60) - 1;
881             }
882             rc = over >= 5 ? RoundingClass.UPPER : RoundingClass.LOWER;
883         }
884     }
885     else
886     {
887         // medium sized number, probably with integer and fractional digits
888         // this is fastest, because both parts fit into a ulong each
889         ulong int_part = mnt >> (T.mant_dig - 1 - exp);
890         ulong frac_part = mnt & ((1L << (T.mant_dig - 1 - exp)) - 1);
891 
892         // for x87 reals the mantiassa might be up to 3 bits too long
893         // we need to save these bits as a tail and handle this separately
894         static if (is(T == real) && real.mant_dig == 64)
895         {
896             ulong tail = 0;
897             ulong tail_length = 0;
898             if (exp < 3)
899             {
900                 tail = frac_part & ((1L << (3 - exp)) - 1);
901                 tail_length = 3 - exp;
902                 frac_part >>= 3 - exp;
903                 exp = 3;
904             }
905         }
906 
907         start = 0;
908 
909         // could we already decide on the rounding mode in the integer part?
910         bool found = false;
911 
912         if (int_part > 0)
913         {
914             import core.bitop : bsr;
915             left = right = int_part.bsr * 100 / 332 + 4;
916 
917             // integer part, if there is something to print
918             while (int_part >= 10)
919             {
920                 dec_buf[--left] = '0' + (int_part % 10);
921                 int_part /= 10;
922                 ++final_exp;
923                 ++start;
924             }
925 
926             dec_buf[--left] = '.';
927             dec_buf[--left] = cast(byte) ('0' + int_part);
928 
929             static if (g)
930                 auto limit = f.precision + 1;
931             else
932                 auto limit = f.precision + 2;
933 
934             if (right - left > limit)
935             {
936                 auto old_right = right;
937                 right = left + limit;
938 
939                 if (dec_buf[right] == '5' || dec_buf[right] == '0')
940                 {
941                     rc = dec_buf[right] == '5' ? RoundingClass.FIVE : RoundingClass.ZERO;
942                     if (frac_part != 0)
943                         rc = rc == RoundingClass.FIVE ? RoundingClass.UPPER : RoundingClass.LOWER;
944                     else
945                         foreach (i;right + 1 .. old_right)
946                             if (dec_buf[i] > '0')
947                             {
948                                 rc = rc == RoundingClass.FIVE ? RoundingClass.UPPER : RoundingClass.LOWER;
949                                 break;
950                             }
951                 }
952                 else
953                     rc = dec_buf[right] > '5' ? RoundingClass.UPPER : RoundingClass.LOWER;
954                 found = true;
955             }
956         }
957         else
958         {
959             // fractional part, skipping leading zeros
960             while (frac_part != 0)
961             {
962                 --final_exp;
963                 frac_part *= 10;
964                 static if (is(T == real) && real.mant_dig == 64)
965                 {
966                     if (tail_length > 0)
967                     {
968                         // together this is *= 10;
969                         tail *= 5;
970                         tail_length--;
971 
972                         frac_part += tail >> tail_length;
973                         if (tail_length > 0)
974                             tail &= (1L << tail_length) - 1;
975                     }
976                 }
977                 auto tmp = frac_part >> (T.mant_dig - 1 - exp);
978                 frac_part &= ((1L << (T.mant_dig - 1 - exp)) - 1);
979                 if (tmp > 0)
980                 {
981                     dec_buf[right++] = cast(byte) ('0' + tmp);
982                     dec_buf[right++] = '.';
983                     break;
984                 }
985             }
986 
987             rc = RoundingClass.ZERO;
988         }
989 
990         static if (g)
991             size_t limit = f.precision - 1;
992         else
993             size_t limit = f.precision;
994 
995         // the fractional part after the zeros
996         while (frac_part != 0 && start < limit)
997         {
998             frac_part *= 10;
999             static if (is(T == real) && real.mant_dig == 64)
1000             {
1001                 if (tail_length > 0)
1002                 {
1003                     // together this is *= 10;
1004                     tail *= 5;
1005                     tail_length--;
1006 
1007                     frac_part += tail >> tail_length;
1008                     if (tail_length > 0)
1009                         tail &= (1L << tail_length) - 1;
1010                 }
1011             }
1012             dec_buf[right++] = cast(byte) ('0' + (frac_part >> (T.mant_dig - 1 - exp)));
1013             frac_part &= ((1L << (T.mant_dig - 1 - exp)) - 1);
1014             ++start;
1015         }
1016 
1017         static if (g)
1018             limit = right - left - 1;
1019         else
1020             limit = start;
1021 
1022         // rounding mode, if not allready known
1023         if (frac_part != 0 && !found)
1024         {
1025             frac_part *= 10;
1026             auto nextDigit = frac_part >> (T.mant_dig - 1 - exp);
1027             frac_part &= ((1L << (T.mant_dig - 1 - exp)) - 1);
1028 
1029             if (nextDigit == 5 && frac_part == 0)
1030                 rc = RoundingClass.FIVE;
1031             else if (nextDigit >= 5)
1032                 rc = RoundingClass.UPPER;
1033             else
1034                 rc = RoundingClass.LOWER;
1035         }
1036     }
1037 
1038     if (round(dec_buf, left, right, rc, sgn == "-"))
1039     {
1040         left--;
1041         right--;
1042         dec_buf[left + 2] = dec_buf[left + 1];
1043         dec_buf[left + 1] = '.';
1044         final_exp++;
1045     }
1046 
1047     // printing exponent
1048     auto neg = final_exp < 0;
1049     if (neg) final_exp = -final_exp;
1050 
1051     size_t exp_pos = exp_buf.length;
1052 
1053     do
1054     {
1055         exp_buf[--exp_pos] = '0' + final_exp%10;
1056         final_exp /= 10;
1057     } while (final_exp > 0);
1058     if (exp_buf.length - exp_pos == 1)
1059         exp_buf[--exp_pos] = '0';
1060     exp_buf[--exp_pos] = neg ? '-' : '+';
1061     exp_buf[--exp_pos] = is_upper ? 'E' : 'e';
1062 
1063     while (right > left + 1 && dec_buf[right - 1] == '0') right--;
1064 
1065     if (right == left + 1)
1066         dec_buf[right++] = '.';
1067 
1068     static if (g)
1069         writeAligned(w, sgn, dec_buf[left .. left + 1], dec_buf[left + 1 .. right],
1070                      exp_buf[exp_pos .. $], f, PrecisionType.allDigits);
1071     else
1072         writeAligned(w, sgn, dec_buf[left .. left + 1], dec_buf[left + 1 .. right],
1073                      exp_buf[exp_pos .. $], f, PrecisionType.fractionalDigits);
1074 }
1075 
1076 @safe unittest
1077 {
1078     auto f = FormatSpec!dchar("");
1079     f.spec = 'e';
1080     assert(printFloat(float.nan, f) == "nan");
1081     assert(printFloat(-float.nan, f) == "-nan");
1082     assert(printFloat(float.infinity, f) == "inf");
1083     assert(printFloat(-float.infinity, f) == "-inf");
1084     assert(printFloat(0.0f, f) == "0.000000e+00");
1085     assert(printFloat(-0.0f, f) == "-0.000000e+00");
1086     // cast needed due to https://issues.dlang.org/show_bug.cgi?id=20361
1087     assert(printFloat(cast(float) 1e-40, f) == "9.999946e-41");
1088     assert(printFloat(cast(float) -1e-40, f) == "-9.999946e-41");
1089     assert(printFloat(1e-30f, f) == "1.000000e-30");
1090     assert(printFloat(-1e-30f, f) == "-1.000000e-30");
1091     assert(printFloat(1e-10f, f) == "1.000000e-10");
1092     assert(printFloat(-1e-10f, f) == "-1.000000e-10");
1093     assert(printFloat(0.1f, f) == "1.000000e-01");
1094     assert(printFloat(-0.1f, f) == "-1.000000e-01");
1095     assert(printFloat(10.0f, f) == "1.000000e+01");
1096     assert(printFloat(-10.0f, f) == "-1.000000e+01");
1097     assert(printFloat(1e30f, f) == "1.000000e+30");
1098     assert(printFloat(-1e30f, f) == "-1.000000e+30");
1099 
1100     import std.math.operations : nextUp, nextDown;
1101     assert(printFloat(nextUp(0.0f), f) == "1.401298e-45");
1102     assert(printFloat(nextDown(-0.0f), f) == "-1.401298e-45");
1103 }
1104 
1105 @safe unittest
1106 {
1107     auto f = FormatSpec!dchar("");
1108     f.spec = 'e';
1109     f.width = 20;
1110     f.precision = 10;
1111 
1112     assert(printFloat(float.nan, f) == "                 nan");
1113     assert(printFloat(-float.nan, f) == "                -nan");
1114     assert(printFloat(float.infinity, f) == "                 inf");
1115     assert(printFloat(-float.infinity, f) == "                -inf");
1116     assert(printFloat(0.0f, f) == "    0.0000000000e+00");
1117     assert(printFloat(-0.0f, f) == "   -0.0000000000e+00");
1118     // cast needed due to https://issues.dlang.org/show_bug.cgi?id=20361
1119     assert(printFloat(cast(float) 1e-40, f) == "    9.9999461011e-41");
1120     assert(printFloat(cast(float) -1e-40, f) == "   -9.9999461011e-41");
1121     assert(printFloat(1e-30f, f) == "    1.0000000032e-30");
1122     assert(printFloat(-1e-30f, f) == "   -1.0000000032e-30");
1123     assert(printFloat(1e-10f, f) == "    1.0000000134e-10");
1124     assert(printFloat(-1e-10f, f) == "   -1.0000000134e-10");
1125     assert(printFloat(0.1f, f) == "    1.0000000149e-01");
1126     assert(printFloat(-0.1f, f) == "   -1.0000000149e-01");
1127     assert(printFloat(10.0f, f) == "    1.0000000000e+01");
1128     assert(printFloat(-10.0f, f) == "   -1.0000000000e+01");
1129     assert(printFloat(1e30f, f) == "    1.0000000150e+30");
1130     assert(printFloat(-1e30f, f) == "   -1.0000000150e+30");
1131 
1132     import std.math.operations : nextUp, nextDown;
1133     assert(printFloat(nextUp(0.0f), f) == "    1.4012984643e-45");
1134     assert(printFloat(nextDown(-0.0f), f) == "   -1.4012984643e-45");
1135 }
1136 
1137 @safe unittest
1138 {
1139     auto f = FormatSpec!dchar("");
1140     f.spec = 'e';
1141     f.width = 20;
1142     f.precision = 10;
1143     f.flDash = true;
1144 
1145     assert(printFloat(float.nan, f) == "nan                 ");
1146     assert(printFloat(-float.nan, f) == "-nan                ");
1147     assert(printFloat(float.infinity, f) == "inf                 ");
1148     assert(printFloat(-float.infinity, f) == "-inf                ");
1149     assert(printFloat(0.0f, f) == "0.0000000000e+00    ");
1150     assert(printFloat(-0.0f, f) == "-0.0000000000e+00   ");
1151     // cast needed due to https://issues.dlang.org/show_bug.cgi?id=20361
1152     assert(printFloat(cast(float) 1e-40, f) == "9.9999461011e-41    ");
1153     assert(printFloat(cast(float) -1e-40, f) == "-9.9999461011e-41   ");
1154     assert(printFloat(1e-30f, f) == "1.0000000032e-30    ");
1155     assert(printFloat(-1e-30f, f) == "-1.0000000032e-30   ");
1156     assert(printFloat(1e-10f, f) == "1.0000000134e-10    ");
1157     assert(printFloat(-1e-10f, f) == "-1.0000000134e-10   ");
1158     assert(printFloat(0.1f, f) == "1.0000000149e-01    ");
1159     assert(printFloat(-0.1f, f) == "-1.0000000149e-01   ");
1160     assert(printFloat(10.0f, f) == "1.0000000000e+01    ");
1161     assert(printFloat(-10.0f, f) == "-1.0000000000e+01   ");
1162     assert(printFloat(1e30f, f) == "1.0000000150e+30    ");
1163     assert(printFloat(-1e30f, f) == "-1.0000000150e+30   ");
1164 
1165     import std.math.operations : nextUp, nextDown;
1166     assert(printFloat(nextUp(0.0f), f) == "1.4012984643e-45    ");
1167     assert(printFloat(nextDown(-0.0f), f) == "-1.4012984643e-45   ");
1168 }
1169 
1170 @safe unittest
1171 {
1172     auto f = FormatSpec!dchar("");
1173     f.spec = 'e';
1174     f.width = 20;
1175     f.precision = 10;
1176     f.flZero = true;
1177 
1178     assert(printFloat(float.nan, f) == "                 nan");
1179     assert(printFloat(-float.nan, f) == "                -nan");
1180     assert(printFloat(float.infinity, f) == "                 inf");
1181     assert(printFloat(-float.infinity, f) == "                -inf");
1182     assert(printFloat(0.0f, f) == "00000.0000000000e+00");
1183     assert(printFloat(-0.0f, f) == "-0000.0000000000e+00");
1184     // cast needed due to https://issues.dlang.org/show_bug.cgi?id=20361
1185     assert(printFloat(cast(float) 1e-40, f) == "00009.9999461011e-41");
1186     assert(printFloat(cast(float) -1e-40, f) == "-0009.9999461011e-41");
1187     assert(printFloat(1e-30f, f) == "00001.0000000032e-30");
1188     assert(printFloat(-1e-30f, f) == "-0001.0000000032e-30");
1189     assert(printFloat(1e-10f, f) == "00001.0000000134e-10");
1190     assert(printFloat(-1e-10f, f) == "-0001.0000000134e-10");
1191     assert(printFloat(0.1f, f) == "00001.0000000149e-01");
1192     assert(printFloat(-0.1f, f) == "-0001.0000000149e-01");
1193     assert(printFloat(10.0f, f) == "00001.0000000000e+01");
1194     assert(printFloat(-10.0f, f) == "-0001.0000000000e+01");
1195     assert(printFloat(1e30f, f) == "00001.0000000150e+30");
1196     assert(printFloat(-1e30f, f) == "-0001.0000000150e+30");
1197 
1198     import std.math.operations : nextUp, nextDown;
1199     assert(printFloat(nextUp(0.0f), f) == "00001.4012984643e-45");
1200     assert(printFloat(nextDown(-0.0f), f) == "-0001.4012984643e-45");
1201 }
1202 
1203 @safe unittest
1204 {
1205     import std.math.hardware; // cannot be selective, because FloatingPointControl might not be defined
1206 
1207     // std.math's FloatingPointControl isn't available on all target platforms
1208     static if (is(FloatingPointControl))
1209     {
1210         FloatingPointControl fpctrl;
1211 
1212         auto f = FormatSpec!dchar("");
1213         f.spec = 'e';
1214         f.precision = 1;
1215 
1216         fpctrl.rounding = FloatingPointControl.roundToNearest;
1217 
1218         /*
1219         assert(printFloat(11.5f, f) == "1.2e+01");
1220         assert(printFloat(12.5f, f) == "1.3e+01");
1221         assert(printFloat(11.7f, f) == "1.2e+01");
1222         assert(printFloat(11.3f, f) == "1.1e+01");
1223         assert(printFloat(11.0f, f) == "1.1e+01");
1224         assert(printFloat(-11.5f, f) == "-1.2e+01");
1225         assert(printFloat(-12.5f, f) == "-1.3e+01");
1226         assert(printFloat(-11.7f, f) == "-1.2e+01");
1227         assert(printFloat(-11.3f, f) == "-1.1e+01");
1228         assert(printFloat(-11.0f, f) == "-1.1e+01");
1229          */
1230 
1231         assert(printFloat(11.5f, f) == "1.2e+01");
1232         assert(printFloat(12.5f, f) == "1.2e+01");
1233         assert(printFloat(11.7f, f) == "1.2e+01");
1234         assert(printFloat(11.3f, f) == "1.1e+01");
1235         assert(printFloat(11.0f, f) == "1.1e+01");
1236         assert(printFloat(-11.5f, f) == "-1.2e+01");
1237         assert(printFloat(-12.5f, f) == "-1.2e+01");
1238         assert(printFloat(-11.7f, f) == "-1.2e+01");
1239         assert(printFloat(-11.3f, f) == "-1.1e+01");
1240         assert(printFloat(-11.0f, f) == "-1.1e+01");
1241 
1242         fpctrl.rounding = FloatingPointControl.roundToZero;
1243 
1244         assert(printFloat(11.5f, f) == "1.1e+01");
1245         assert(printFloat(12.5f, f) == "1.2e+01");
1246         assert(printFloat(11.7f, f) == "1.1e+01");
1247         assert(printFloat(11.3f, f) == "1.1e+01");
1248         assert(printFloat(11.0f, f) == "1.1e+01");
1249         assert(printFloat(-11.5f, f) == "-1.1e+01");
1250         assert(printFloat(-12.5f, f) == "-1.2e+01");
1251         assert(printFloat(-11.7f, f) == "-1.1e+01");
1252         assert(printFloat(-11.3f, f) == "-1.1e+01");
1253         assert(printFloat(-11.0f, f) == "-1.1e+01");
1254 
1255         fpctrl.rounding = FloatingPointControl.roundUp;
1256 
1257         assert(printFloat(11.5f, f) == "1.2e+01");
1258         assert(printFloat(12.5f, f) == "1.3e+01");
1259         assert(printFloat(11.7f, f) == "1.2e+01");
1260         assert(printFloat(11.3f, f) == "1.2e+01");
1261         assert(printFloat(11.0f, f) == "1.1e+01");
1262         assert(printFloat(-11.5f, f) == "-1.1e+01");
1263         assert(printFloat(-12.5f, f) == "-1.2e+01");
1264         assert(printFloat(-11.7f, f) == "-1.1e+01");
1265         assert(printFloat(-11.3f, f) == "-1.1e+01");
1266         assert(printFloat(-11.0f, f) == "-1.1e+01");
1267 
1268         fpctrl.rounding = FloatingPointControl.roundDown;
1269 
1270         assert(printFloat(11.5f, f) == "1.1e+01");
1271         assert(printFloat(12.5f, f) == "1.2e+01");
1272         assert(printFloat(11.7f, f) == "1.1e+01");
1273         assert(printFloat(11.3f, f) == "1.1e+01");
1274         assert(printFloat(11.0f, f) == "1.1e+01");
1275         assert(printFloat(-11.5f, f) == "-1.2e+01");
1276         assert(printFloat(-12.5f, f) == "-1.3e+01");
1277         assert(printFloat(-11.7f, f) == "-1.2e+01");
1278         assert(printFloat(-11.3f, f) == "-1.2e+01");
1279         assert(printFloat(-11.0f, f) == "-1.1e+01");
1280     }
1281 }
1282 
1283 @safe unittest
1284 {
1285     auto f = FormatSpec!dchar("");
1286     f.spec = 'e';
1287     assert(printFloat(double.nan, f) == "nan");
1288     assert(printFloat(-double.nan, f) == "-nan");
1289     assert(printFloat(double.infinity, f) == "inf");
1290     assert(printFloat(-double.infinity, f) == "-inf");
1291     assert(printFloat(0.0, f) == "0.000000e+00");
1292     assert(printFloat(-0.0, f) == "-0.000000e+00");
1293     // / 1000 needed due to https://issues.dlang.org/show_bug.cgi?id=20361
1294     assert(printFloat(1e-307 / 1000, f) == "1.000000e-310");
1295     assert(printFloat(-1e-307 / 1000, f) == "-1.000000e-310");
1296     assert(printFloat(1e-30, f) == "1.000000e-30");
1297     assert(printFloat(-1e-30, f) == "-1.000000e-30");
1298     assert(printFloat(1e-10, f) == "1.000000e-10");
1299     assert(printFloat(-1e-10, f) == "-1.000000e-10");
1300     assert(printFloat(0.1, f) == "1.000000e-01");
1301     assert(printFloat(-0.1, f) == "-1.000000e-01");
1302     assert(printFloat(10.0, f) == "1.000000e+01");
1303     assert(printFloat(-10.0, f) == "-1.000000e+01");
1304     assert(printFloat(1e300, f) == "1.000000e+300");
1305     assert(printFloat(-1e300, f) == "-1.000000e+300");
1306 
1307     import std.math.operations : nextUp, nextDown;
1308     assert(printFloat(nextUp(0.0), f) == "4.940656e-324");
1309     assert(printFloat(nextDown(-0.0), f) == "-4.940656e-324");
1310 }
1311 
1312 @safe unittest
1313 {
1314     static if (real.mant_dig > 64)
1315     {
1316         pragma(msg, "printFloat tests disabled because of unsupported `real` format");
1317     }
1318     else
1319     {
1320         auto f = FormatSpec!dchar("");
1321         f.spec = 'e';
1322         assert(printFloat(real.nan, f) == "nan");
1323         assert(printFloat(-real.nan, f) == "-nan");
1324         assert(printFloat(real.infinity, f) == "inf");
1325         assert(printFloat(-real.infinity, f) == "-inf");
1326     }
1327 }
1328 
1329 @safe unittest
1330 {
1331     auto f = FormatSpec!dchar("");
1332     f.spec = 'e';
1333 
1334     import std.math.operations : nextUp;
1335 
1336     double eps = nextUp(0.0);
1337     f.precision = 1000;
1338     assert(printFloat(eps, f) ==
1339            "4.9406564584124654417656879286822137236505980261432476442558568250067550727020875186529983636163599"
1340            ~"23797965646954457177309266567103559397963987747960107818781263007131903114045278458171678489821036"
1341            ~"88718636056998730723050006387409153564984387312473397273169615140031715385398074126238565591171026"
1342            ~"65855668676818703956031062493194527159149245532930545654440112748012970999954193198940908041656332"
1343            ~"45247571478690147267801593552386115501348035264934720193790268107107491703332226844753335720832431"
1344            ~"93609238289345836806010601150616980975307834227731832924790498252473077637592724787465608477820373"
1345            ~"44696995336470179726777175851256605511991315048911014510378627381672509558373897335989936648099411"
1346            ~"64205702637090279242767544565229087538682506419718265533447265625000000000000000000000000000000000"
1347            ~"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
1348            ~"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
1349            ~"000000000000000000000e-324");
1350 
1351     f.precision = 50;
1352     assert(printFloat(double.max, f) ==
1353            "1.79769313486231570814527423731704356798070567525845e+308");
1354     assert(printFloat(double.epsilon, f) ==
1355            "2.22044604925031308084726333618164062500000000000000e-16");
1356 
1357     f.precision = 10;
1358     assert(printFloat(1.0/3.0, f) == "3.3333333333e-01");
1359     assert(printFloat(1.0/7.0, f) == "1.4285714286e-01");
1360     assert(printFloat(1.0/9.0, f) == "1.1111111111e-01");
1361 }
1362 
1363 @safe unittest
1364 {
1365     auto f = FormatSpec!dchar("");
1366     f.spec = 'e';
1367     f.precision = 15;
1368 
1369     import std.math.constants : E, PI, PI_2, PI_4, M_1_PI, M_2_PI, M_2_SQRTPI,
1370                                 LN10, LN2, LOG2, LOG2E, LOG2T, LOG10E, SQRT2, SQRT1_2;
1371 
1372     assert(printFloat(cast(double) E, f) == "2.718281828459045e+00");
1373     assert(printFloat(cast(double) PI, f) == "3.141592653589793e+00");
1374     assert(printFloat(cast(double) PI_2, f) == "1.570796326794897e+00");
1375     assert(printFloat(cast(double) PI_4, f) == "7.853981633974483e-01");
1376     assert(printFloat(cast(double) M_1_PI, f) == "3.183098861837907e-01");
1377     assert(printFloat(cast(double) M_2_PI, f) == "6.366197723675814e-01");
1378     assert(printFloat(cast(double) M_2_SQRTPI, f) == "1.128379167095513e+00");
1379     assert(printFloat(cast(double) LN10, f) == "2.302585092994046e+00");
1380     assert(printFloat(cast(double) LN2, f) == "6.931471805599453e-01");
1381     assert(printFloat(cast(double) LOG2, f) == "3.010299956639812e-01");
1382     assert(printFloat(cast(double) LOG2E, f) == "1.442695040888963e+00");
1383     assert(printFloat(cast(double) LOG2T, f) == "3.321928094887362e+00");
1384     assert(printFloat(cast(double) LOG10E, f) == "4.342944819032518e-01");
1385     assert(printFloat(cast(double) SQRT2, f) == "1.414213562373095e+00");
1386     assert(printFloat(cast(double) SQRT1_2, f) == "7.071067811865476e-01");
1387 }
1388 
1389 // for 100% coverage
1390 @safe unittest
1391 {
1392     import std.math.hardware; // cannot be selective, because FloatingPointControl might not be defined
1393 
1394     auto f = FormatSpec!dchar("");
1395     f.spec = 'E';
1396     f.precision = 80;
1397     assert(printFloat(5.62776e+12f, f) ==
1398            "5.62775982080000000000000000000000000000000000000000000000000000000000000000000000E+12");
1399 
1400     f.precision = 49;
1401     assert(printFloat(2.5997869e-12f, f) ==
1402            "2.5997869221999758693186777236405760049819946289062E-12");
1403 
1404     f.precision = 6;
1405     assert(printFloat(-1.1418613e+07f, f) == "-1.141861E+07");
1406     assert(printFloat(-1.368281e+07f, f) == "-1.368281E+07");
1407 
1408     f.precision = 1;
1409     assert(printFloat(-245.666f, f) == "-2.5E+02");
1410 
1411     static if (is(FloatingPointControl))
1412     {
1413         FloatingPointControl fpctrl;
1414 
1415         fpctrl.rounding = FloatingPointControl.roundUp;
1416 
1417         f.precision = 0;
1418         assert(printFloat(709422.0f, f) == "8E+05");
1419     }
1420 }
1421 
1422 @safe unittest
1423 {
1424     static if (real.mant_dig > 64)
1425     {
1426         pragma(msg, "printFloat tests disabled because of unsupported `real` format");
1427     }
1428     else
1429     {
1430         auto f = FormatSpec!dchar("");
1431         f.spec = 'e';
1432         assert(printFloat(real.nan, f) == "nan");
1433         assert(printFloat(-real.nan, f) == "-nan");
1434         assert(printFloat(real.infinity, f) == "inf");
1435         assert(printFloat(-real.infinity, f) == "-inf");
1436         assert(printFloat(0.0L, f) == "0.000000e+00");
1437         assert(printFloat(-0.0L, f) == "-0.000000e+00");
1438     }
1439 
1440     static if (real.mant_dig == 64)
1441     {
1442         assert(printFloat(1e-4940L, f) == "1.000000e-4940");
1443         assert(printFloat(-1e-4940L, f) == "-1.000000e-4940");
1444         assert(printFloat(1e-30L, f) == "1.000000e-30");
1445         assert(printFloat(-1e-30L, f) == "-1.000000e-30");
1446         assert(printFloat(1e-10L, f) == "1.000000e-10");
1447         assert(printFloat(-1e-10L, f) == "-1.000000e-10");
1448         assert(printFloat(0.1L, f) == "1.000000e-01");
1449         assert(printFloat(-0.1L, f) == "-1.000000e-01");
1450         assert(printFloat(10.0L, f) == "1.000000e+01");
1451         assert(printFloat(-10.0L, f) == "-1.000000e+01");
version(Windows)1452         version (Windows) {} // issue 20972
1453         else
1454         {
1455             assert(printFloat(1e4000L, f) == "1.000000e+4000");
1456             assert(printFloat(-1e4000L, f) == "-1.000000e+4000");
1457         }
1458 
1459         import std.math.operations : nextUp, nextDown;
1460         assert(printFloat(nextUp(0.0L), f) == "3.645200e-4951");
1461         assert(printFloat(nextDown(-0.0L), f) == "-3.645200e-4951");
1462     }
1463 }
1464 
1465 @safe unittest
1466 {
1467     import std.exception : assertCTFEable;
1468     import std.math.exponential : log2;
1469     import std.math.operations : nextDown;
1470 
1471     assertCTFEable!(
1472     {
1473         // log2 is broken for x87-reals on some computers in CTFE
1474         // the following tests excludes these computers from the tests
1475         // (issue 21757)
1476         enum test = cast(int) log2(3.05e2312L);
1477         static if (real.mant_dig == 64 && test == 7681)
1478         {
1479             auto f = FormatSpec!dchar("");
1480             f.spec = 'e';
1481             assert(printFloat(real.infinity, f) == "inf");
1482             assert(printFloat(10.0L, f) == "1.000000e+01");
1483             assert(printFloat(2.6080L, f) == "2.608000e+00");
1484             assert(printFloat(3.05e2312L, f) == "3.050000e+2312");
1485 
1486             f.precision = 60;
1487             assert(printFloat(2.65e-54L, f) ==
1488                    "2.650000000000000000059009987400547013941028940935296547599415e-54");
1489 
1490             /*
1491              commented out, because CTFE is currently too slow for 5000 digits with extreme values
1492 
1493             f.precision = 5000;
1494             auto result2 = printFloat(1.2119e-4822L, f);
1495             assert(result2.length == 5008);
1496             assert(result2[$ - 20 .. $] == "60729486595339e-4822");
1497             auto result3 = printFloat(real.min_normal, f);
1498             assert(result3.length == 5008);
1499             assert(result3[$ - 20 .. $] == "20781410082267e-4932");
1500             auto result4 = printFloat(real.min_normal.nextDown, f);
1501             assert(result4.length == 5008);
1502             assert(result4[$ - 20 .. $] == "81413263331006e-4932");
1503              */
1504         }
1505     });
1506 }
1507 
1508 private void printFloatF(bool g, Writer, T, Char)(auto ref Writer w, const(T) val,
1509     FormatSpec!Char f, string sgn, int exp, ulong mnt, bool is_upper)
1510 if (is(T == float) || is(T == double)
1511     || (is(T == real) && (T.mant_dig == double.mant_dig || T.mant_dig == 64)))
1512 {
1513     import std.format.internal.write : writeAligned, PrecisionType, RoundingClass, round;
1514 
1515     static if (!g)
1516     {
1517         if (f.precision == f.UNSPECIFIED)
1518             f.precision = 6;
1519     }
1520 
1521     // special treatment for 0.0
1522     if (exp == 0 && mnt == 0)
1523     {
1524         writeAligned(w, sgn, "0", ".", "", f, PrecisionType.fractionalDigits);
1525         return;
1526     }
1527 
1528     char[T.max_exp + T.mant_dig + 1] dec_buf;
1529 
1530     RoundingClass rc;
1531 
1532     // Depending on exp, we will use one of three algorithms:
1533     //
1534     // Algorithm A: For large exponents (exp >= T.mant_dig)
1535     // Algorithm B: For small exponents (exp < T.mant_dig - 61)
1536     // Algorithm C: For exponents close to 0.
1537     //
1538     // Algorithm A:
1539     //   The number to print looks like this: mantissa followed by several zeros.
1540     //
1541     //   We know, that there is no fractional part, so we can just use integer division,
1542     //   consecutivly dividing by 10 and writing down the remainder from right to left.
1543     //   Unfortunately the integer is too large to fit in an ulong, so we use something
1544     //   like BigInt: An array of ulongs. We only use 60 bits of that ulongs, because
1545     //   this simplifies (and speeds up) the division to come.
1546     //
1547     //   For the division we use integer division with reminder for each ulong and put
1548     //   the reminder of each step in the first 4 bits of ulong of the next step (think of
1549     //   long division for the rationale behind this). The final reminder is the next
1550     //   digit (from right to left).
1551     //
1552     // Algorithm B:
1553     //   The number to print looks like this: zero dot several zeros followed by the mantissa
1554     //
1555     //   We know, that the number has no integer part. The algorithm consecutivly multiplies
1556     //   by 10. The integer part (rounded down) after the multiplication is the next digit
1557     //   (from left to right). This integer part is removed after each step.
1558     //   Again, the number is represented as an array of ulongs, with only 60 bits used of
1559     //   every ulong.
1560     //
1561     //   For the multiplication we use normal integer multiplication, which can result in digits
1562     //   in the uppermost 4 bits. These 4 digits are the carry which is added to the result
1563     //   of the next multiplication and finally the last carry is the next digit.
1564     //
1565     //   The calculation will stop, when only zeros remain or when we've got enough digits
1566     //   for the requested precision. In the second case, we have to find out, which rounding
1567     //   we have. Aside from special cases we do this by calculating one more digit.
1568     //
1569     // Algorithm C:
1570     //   This time, we know, that the integral part and the fractional part each fit into a
1571     //   ulong. The mantissa might be partially in both parts or completely in the fractional
1572     //   part.
1573     //
1574     //   We first calculate the integral part by consecutive division by 10. Then we calculate
1575     //   the fractional part by consecutive multiplication by 10. Again only until we have enough
1576     //   digits. Finally, we decide the rounding type, mainly by looking at the next digit.
1577 
1578     static if (is(T == real) && real.mant_dig == 64)
1579     {
1580         enum small_bound = 0;
1581         enum max_buf = 275;
1582     }
1583     else
1584     {
1585         enum small_bound = T.mant_dig - 61;
1586         static if (is(T == float))
1587             enum max_buf = 4;
1588         else
1589             enum max_buf = 18;
1590     }
1591 
1592     size_t start = 2;
1593     size_t left = 2;
1594     size_t right = 2;
1595 
1596     ulong[max_buf] bigbuf;
1597     if (exp >= T.mant_dig)
1598     {
1599         left = start = dec_buf.length - 1;
1600         right = dec_buf.length;
1601         dec_buf[start] = '.';
1602 
1603         // large number without fractional digits
1604         //
1605         // As this number does not fit in a ulong, we use an array of ulongs. We only use 60 of the 64 bits,
1606         // because this makes it much more easy to implement the division by 10.
1607         int count = exp / 60 + 1;
1608 
1609         // only the first few ulongs contain the mantiassa. The rest are zeros.
1610         int lower = 60 - (exp - T.mant_dig + 1) % 60;
1611 
1612         static if (is(T == real) && real.mant_dig == 64)
1613         {
1614             // for x87 reals, the lowest ulong may contain more than 60 bits,
1615             // because the mantissa is 63 (>60) bits long
1616             // therefore we need one ulong less
1617             if (lower <= 3) count--;
1618         }
1619 
1620         // saved in big endian format
1621         ulong[] mybig = bigbuf[0 .. count];
1622 
1623         if (lower < T.mant_dig)
1624         {
1625             mybig[0] = mnt >> lower;
1626             mybig[1] = (mnt & ((1L << lower) - 1)) << 60 - lower;
1627         }
1628         else
1629             mybig[0] = (mnt & ((1L << lower) - 1)) << 60 - lower;
1630 
1631         // Generation of digits by consecutive division with reminder by 10.
1632         int msu = 0; // Most significant ulong; when it get's zero, we can ignore it furtheron
1633         while (msu < count - 1 || mybig[$ - 1] != 0)
1634         {
1635             ulong mod = 0;
foreach(i;msu..count)1636             foreach (i;msu .. count)
1637             {
1638                 mybig[i] |= mod << 60;
1639                 mod = mybig[i] % 10;
1640                 mybig[i] /= 10;
1641             }
1642             if (mybig[msu] == 0)
1643                 ++msu;
1644 
1645             dec_buf[--left] = cast(byte) ('0' + mod);
1646         }
1647 
1648         rc = RoundingClass.ZERO;
1649     }
1650     else if (exp < small_bound)
1651     {
1652         // small number without integer digits
1653         //
1654         // Again this number does not fit in a ulong and we use an array of ulongs. And again we
1655         // only use 60 bits, because this simplifies the multiplication by 10.
1656         int count = (T.mant_dig - exp - 2) / 60 + 1;
1657 
1658         // saved in little endian format
1659         ulong[] mybig = bigbuf[0 .. count];
1660 
1661         // only the last few ulongs contain the mantiassa. Because of little endian
1662         // format these are the ulongs at index 0 and 1 (and 2 in case of x87 reals).
1663         // The rest are zeros.
1664         int upper = 60 - (-exp - 1) % 60;
1665 
1666         static if (is(T == real) && real.mant_dig == 64)
1667         {
1668             if (upper < 4)
1669             {
1670                 mybig[0] = (mnt & ((1L << (4 - upper)) - 1)) << 56 + upper;
1671                 mybig[1] = (mnt >> (4 - upper)) & ((1L << 60) - 1);
1672                 mybig[2] = mnt >> 64 - upper;
1673             }
1674             else
1675             {
1676                 mybig[0] = (mnt & ((1L << (T.mant_dig - upper)) - 1)) << 60 - (T.mant_dig - upper);
1677                 mybig[1] = mnt >> (T.mant_dig - upper);
1678             }
1679         }
1680         else
1681         {
1682             if (upper < T.mant_dig)
1683             {
1684                 mybig[0] = (mnt & ((1L << (T.mant_dig - upper)) - 1)) << 60 - (T.mant_dig - upper);
1685                 mybig[1] = mnt >> (T.mant_dig - upper);
1686             }
1687             else
1688                 mybig[0] = mnt << (upper - T.mant_dig);
1689         }
1690 
1691         dec_buf[--left] = '0'; // 0 left of the dot
1692         dec_buf[right++] = '.';
1693 
1694         static if (g)
1695         {
1696             // precision starts at first non zero, so we move start
1697             // to the right, until we found first non zero, thus avoiding
1698             // a premature break of the loop
1699             bool found = false;
1700             start = left + 1;
1701         }
1702 
1703         // Generation of digits by consecutive multiplication by 10.
1704         int lsu = 0; // Least significant ulong; when it get's zero, we can ignore it furtheron
1705         while ((lsu < count - 1 || mybig[$ - 1] != 0) && right - start - 1 < f.precision)
1706         {
1707             ulong over = 0;
foreach(i;lsu..count)1708             foreach (i;lsu .. count)
1709             {
1710                 mybig[i] = mybig[i] * 10 + over;
1711                 over = mybig[i] >> 60;
1712                 mybig[i] &= (1L << 60) - 1;
1713             }
1714             if (mybig[lsu] == 0)
1715                 ++lsu;
1716 
1717             dec_buf[right++] = cast(byte) ('0' + over);
1718 
1719             static if (g)
1720             {
1721                 if (dec_buf[right - 1] != '0')
1722                     found = true;
1723                 else if (!found)
1724                     start++;
1725             }
1726         }
1727 
1728         static if (g) start = 2;
1729 
1730         if (lsu >= count - 1 && mybig[count - 1] == 0)
1731             rc = RoundingClass.ZERO;
1732         else if (lsu == count - 1 && mybig[lsu] == 1L << 59)
1733             rc = RoundingClass.FIVE;
1734         else
1735         {
1736             ulong over = 0;
foreach(i;lsu..count)1737             foreach (i;lsu .. count)
1738             {
1739                 mybig[i] = mybig[i] * 10 + over;
1740                 over = mybig[i] >> 60;
1741                 mybig[i] &= (1L << 60) - 1;
1742             }
1743             rc = over >= 5 ? RoundingClass.UPPER : RoundingClass.LOWER;
1744         }
1745     }
1746     else
1747     {
1748         // medium sized number, probably with integer and fractional digits
1749         // this is fastest, because both parts fit into a ulong each
1750         ulong int_part = mnt >> (T.mant_dig - 1 - exp);
1751         ulong frac_part = mnt & ((1L << (T.mant_dig - 1 - exp)) - 1);
1752 
1753         // for x87 reals the mantiassa might be up to 3 bits too long
1754         // we need to save these bits as a tail and handle this separately
1755         static if (is(T == real) && real.mant_dig == 64)
1756         {
1757             ulong tail = 0;
1758             ulong tail_length = 0;
1759             if (exp < 3)
1760             {
1761                 tail = frac_part & ((1L << (3 - exp)) - 1);
1762                 tail_length = 3 - exp;
1763                 frac_part >>= 3 - exp;
1764                 exp = 3;
1765             }
1766         }
1767 
1768         static if (g) auto found = int_part > 0; // searching first non zero
1769 
1770         // creating int part
1771         if (int_part == 0)
1772             dec_buf[--left] = '0';
1773         else
1774         {
1775             import core.bitop : bsr;
1776             left = right = start = int_part.bsr * 100 / 332 + 4;
1777 
1778             while (int_part > 0)
1779             {
1780                 dec_buf[--left] = '0' + (int_part % 10);
1781                 int_part /= 10;
1782             }
1783         }
1784 
1785         static if (g) size_t save_start = right;
1786 
1787         dec_buf[right++] = '.';
1788 
1789         // creating frac part
1790         static if (g) start = left + (found ? 0 : 1);
1791         while (frac_part != 0 && right - start - 1 < f.precision)
1792         {
1793             frac_part *= 10;
1794             static if (is(T == real) && real.mant_dig == 64)
1795             {
1796                 if (tail_length > 0)
1797                 {
1798                     // together this is *= 10;
1799                     tail *= 5;
1800                     tail_length--;
1801 
1802                     frac_part += tail >> tail_length;
1803                     if (tail_length > 0)
1804                         tail &= (1L << tail_length) - 1;
1805                 }
1806             }
1807             dec_buf[right++] = cast(byte)('0' + (frac_part >> (T.mant_dig - 1 - exp)));
1808 
1809             static if (g)
1810             {
1811                 if (dec_buf[right - 1] != '0')
1812                     found = true;
1813                 else if (!found)
1814                     start++;
1815             }
1816 
1817             frac_part &= ((1L << (T.mant_dig - 1 - exp)) - 1);
1818         }
1819 
1820         static if (g) start = save_start;
1821 
1822         if (frac_part == 0)
1823             rc = RoundingClass.ZERO;
1824         else
1825         {
1826             frac_part *= 10;
1827             auto nextDigit = frac_part >> (T.mant_dig - 1 - exp);
1828             frac_part &= ((1L << (T.mant_dig - 1 - exp)) - 1);
1829 
1830             if (nextDigit == 5 && frac_part == 0)
1831                 rc = RoundingClass.FIVE;
1832             else if (nextDigit >= 5)
1833                 rc = RoundingClass.UPPER;
1834             else
1835                 rc = RoundingClass.LOWER;
1836         }
1837     }
1838 
1839     if (round(dec_buf, left, right, rc, sgn == "-")) left--;
1840 
1841     while (right > start + 1 && dec_buf[right - 1] == '0') right--;
1842 
1843     static if (g)
1844         writeAligned(w, sgn, dec_buf[left .. start], dec_buf[start .. right], "", f, PrecisionType.allDigits);
1845     else
1846         writeAligned(w, sgn, dec_buf[left .. start], dec_buf[start .. right], "", f, PrecisionType.fractionalDigits);
1847 }
1848 
1849 @safe unittest
1850 {
1851     auto f = FormatSpec!dchar("");
1852     f.spec = 'f';
1853     assert(printFloat(float.nan, f) == "nan");
1854     assert(printFloat(-float.nan, f) == "-nan");
1855     assert(printFloat(float.infinity, f) == "inf");
1856     assert(printFloat(-float.infinity, f) == "-inf");
1857     assert(printFloat(0.0f, f) == "0.000000");
1858     assert(printFloat(-0.0f, f) == "-0.000000");
1859     // cast needed due to https://issues.dlang.org/show_bug.cgi?id=20361
1860     assert(printFloat(cast(float) 1e-40, f) == "0.000000");
1861     assert(printFloat(cast(float) -1e-40, f) == "-0.000000");
1862     assert(printFloat(1e-30f, f) == "0.000000");
1863     assert(printFloat(-1e-30f, f) == "-0.000000");
1864     assert(printFloat(1e-10f, f) == "0.000000");
1865     assert(printFloat(-1e-10f, f) == "-0.000000");
1866     assert(printFloat(0.1f, f) == "0.100000");
1867     assert(printFloat(-0.1f, f) == "-0.100000");
1868     assert(printFloat(10.0f, f) == "10.000000");
1869     assert(printFloat(-10.0f, f) == "-10.000000");
1870     assert(printFloat(1e30f, f) == "1000000015047466219876688855040.000000");
1871     assert(printFloat(-1e30f, f) == "-1000000015047466219876688855040.000000");
1872 
1873     import std.math.operations : nextUp, nextDown;
1874     assert(printFloat(nextUp(0.0f), f) == "0.000000");
1875     assert(printFloat(nextDown(-0.0f), f) == "-0.000000");
1876 }
1877 
1878 @safe unittest
1879 {
1880     auto f = FormatSpec!dchar("");
1881     f.spec = 'f';
1882     f.width = 20;
1883     f.precision = 10;
1884 
1885     assert(printFloat(float.nan, f) == "                 nan");
1886     assert(printFloat(-float.nan, f) == "                -nan");
1887     assert(printFloat(float.infinity, f) == "                 inf");
1888     assert(printFloat(-float.infinity, f) == "                -inf");
1889     assert(printFloat(0.0f, f) == "        0.0000000000");
1890     assert(printFloat(-0.0f, f) == "       -0.0000000000");
1891     // cast needed due to https://issues.dlang.org/show_bug.cgi?id=20361
1892     assert(printFloat(cast(float) 1e-40, f) == "        0.0000000000");
1893     assert(printFloat(cast(float) -1e-40, f) == "       -0.0000000000");
1894     assert(printFloat(1e-30f, f) == "        0.0000000000");
1895     assert(printFloat(-1e-30f, f) == "       -0.0000000000");
1896     assert(printFloat(1e-10f, f) == "        0.0000000001");
1897     assert(printFloat(-1e-10f, f) == "       -0.0000000001");
1898     assert(printFloat(0.1f, f) == "        0.1000000015");
1899     assert(printFloat(-0.1f, f) == "       -0.1000000015");
1900     assert(printFloat(10.0f, f) == "       10.0000000000");
1901     assert(printFloat(-10.0f, f) == "      -10.0000000000");
1902     assert(printFloat(1e30f, f) == "1000000015047466219876688855040.0000000000");
1903     assert(printFloat(-1e30f, f) == "-1000000015047466219876688855040.0000000000");
1904 
1905     import std.math.operations : nextUp, nextDown;
1906     assert(printFloat(nextUp(0.0f), f) == "        0.0000000000");
1907     assert(printFloat(nextDown(-0.0f), f) == "       -0.0000000000");
1908 }
1909 
1910 @safe unittest
1911 {
1912     auto f = FormatSpec!dchar("");
1913     f.spec = 'f';
1914     f.width = 20;
1915     f.precision = 10;
1916     f.flDash = true;
1917 
1918     assert(printFloat(float.nan, f) == "nan                 ");
1919     assert(printFloat(-float.nan, f) == "-nan                ");
1920     assert(printFloat(float.infinity, f) == "inf                 ");
1921     assert(printFloat(-float.infinity, f) == "-inf                ");
1922     assert(printFloat(0.0f, f) == "0.0000000000        ");
1923     assert(printFloat(-0.0f, f) == "-0.0000000000       ");
1924     // cast needed due to https://issues.dlang.org/show_bug.cgi?id=20361
1925     assert(printFloat(cast(float) 1e-40, f) == "0.0000000000        ");
1926     assert(printFloat(cast(float) -1e-40, f) == "-0.0000000000       ");
1927     assert(printFloat(1e-30f, f) == "0.0000000000        ");
1928     assert(printFloat(-1e-30f, f) == "-0.0000000000       ");
1929     assert(printFloat(1e-10f, f) == "0.0000000001        ");
1930     assert(printFloat(-1e-10f, f) == "-0.0000000001       ");
1931     assert(printFloat(0.1f, f) == "0.1000000015        ");
1932     assert(printFloat(-0.1f, f) == "-0.1000000015       ");
1933     assert(printFloat(10.0f, f) == "10.0000000000       ");
1934     assert(printFloat(-10.0f, f) == "-10.0000000000      ");
1935     assert(printFloat(1e30f, f) == "1000000015047466219876688855040.0000000000");
1936     assert(printFloat(-1e30f, f) == "-1000000015047466219876688855040.0000000000");
1937 
1938     import std.math.operations : nextUp, nextDown;
1939     assert(printFloat(nextUp(0.0f), f) == "0.0000000000        ");
1940     assert(printFloat(nextDown(-0.0f), f) == "-0.0000000000       ");
1941 }
1942 
1943 @safe unittest
1944 {
1945     auto f = FormatSpec!dchar("");
1946     f.spec = 'f';
1947     f.width = 20;
1948     f.precision = 10;
1949     f.flZero = true;
1950 
1951     assert(printFloat(float.nan, f) == "                 nan");
1952     assert(printFloat(-float.nan, f) == "                -nan");
1953     assert(printFloat(float.infinity, f) == "                 inf");
1954     assert(printFloat(-float.infinity, f) == "                -inf");
1955     assert(printFloat(0.0f, f) == "000000000.0000000000");
1956     assert(printFloat(-0.0f, f) == "-00000000.0000000000");
1957     // cast needed due to https://issues.dlang.org/show_bug.cgi?id=20361
1958     assert(printFloat(cast(float) 1e-40, f) == "000000000.0000000000");
1959     assert(printFloat(cast(float) -1e-40, f) == "-00000000.0000000000");
1960     assert(printFloat(1e-30f, f) == "000000000.0000000000");
1961     assert(printFloat(-1e-30f, f) == "-00000000.0000000000");
1962     assert(printFloat(1e-10f, f) == "000000000.0000000001");
1963     assert(printFloat(-1e-10f, f) == "-00000000.0000000001");
1964     assert(printFloat(0.1f, f) == "000000000.1000000015");
1965     assert(printFloat(-0.1f, f) == "-00000000.1000000015");
1966     assert(printFloat(10.0f, f) == "000000010.0000000000");
1967     assert(printFloat(-10.0f, f) == "-00000010.0000000000");
1968     assert(printFloat(1e30f, f) == "1000000015047466219876688855040.0000000000");
1969     assert(printFloat(-1e30f, f) == "-1000000015047466219876688855040.0000000000");
1970 
1971     import std.math.operations : nextUp, nextDown;
1972     assert(printFloat(nextUp(0.0f), f) == "000000000.0000000000");
1973     assert(printFloat(nextDown(-0.0f), f) == "-00000000.0000000000");
1974 }
1975 
1976 @safe unittest
1977 {
1978     import std.math.hardware; // cannot be selective, because FloatingPointControl might not be defined
1979 
1980     // std.math's FloatingPointControl isn't available on all target platforms
1981     static if (is(FloatingPointControl))
1982     {
1983         FloatingPointControl fpctrl;
1984 
1985         auto f = FormatSpec!dchar("");
1986         f.spec = 'f';
1987         f.precision = 0;
1988 
1989         fpctrl.rounding = FloatingPointControl.roundToNearest;
1990 
1991         /*
1992          assert(printFloat(11.5f, f) == "12");
1993          assert(printFloat(12.5f, f) == "13");
1994          assert(printFloat(11.7f, f) == "12");
1995          assert(printFloat(11.3f, f) == "11");
1996          assert(printFloat(11.0f, f) == "11");
1997          assert(printFloat(-11.5f, f) == "-12");
1998          assert(printFloat(-12.5f, f) == "-13");
1999          assert(printFloat(-11.7f, f) == "-12");
2000          assert(printFloat(-11.3f, f) == "-11");
2001          assert(printFloat(-11.0f, f) == "-11");
2002          */
2003 
2004         assert(printFloat(11.5f, f) == "12");
2005         assert(printFloat(12.5f, f) == "12");
2006         assert(printFloat(11.7f, f) == "12");
2007         assert(printFloat(11.3f, f) == "11");
2008         assert(printFloat(11.0f, f) == "11");
2009         assert(printFloat(-11.5f, f) == "-12");
2010         assert(printFloat(-12.5f, f) == "-12");
2011         assert(printFloat(-11.7f, f) == "-12");
2012         assert(printFloat(-11.3f, f) == "-11");
2013         assert(printFloat(-11.0f, f) == "-11");
2014 
2015         fpctrl.rounding = FloatingPointControl.roundToZero;
2016 
2017         assert(printFloat(11.5f, f) == "11");
2018         assert(printFloat(12.5f, f) == "12");
2019         assert(printFloat(11.7f, f) == "11");
2020         assert(printFloat(11.3f, f) == "11");
2021         assert(printFloat(11.0f, f) == "11");
2022         assert(printFloat(-11.5f, f) == "-11");
2023         assert(printFloat(-12.5f, f) == "-12");
2024         assert(printFloat(-11.7f, f) == "-11");
2025         assert(printFloat(-11.3f, f) == "-11");
2026         assert(printFloat(-11.0f, f) == "-11");
2027 
2028         fpctrl.rounding = FloatingPointControl.roundUp;
2029 
2030         assert(printFloat(11.5f, f) == "12");
2031         assert(printFloat(12.5f, f) == "13");
2032         assert(printFloat(11.7f, f) == "12");
2033         assert(printFloat(11.3f, f) == "12");
2034         assert(printFloat(11.0f, f) == "11");
2035         assert(printFloat(-11.5f, f) == "-11");
2036         assert(printFloat(-12.5f, f) == "-12");
2037         assert(printFloat(-11.7f, f) == "-11");
2038         assert(printFloat(-11.3f, f) == "-11");
2039         assert(printFloat(-11.0f, f) == "-11");
2040 
2041         fpctrl.rounding = FloatingPointControl.roundDown;
2042 
2043         assert(printFloat(11.5f, f) == "11");
2044         assert(printFloat(12.5f, f) == "12");
2045         assert(printFloat(11.7f, f) == "11");
2046         assert(printFloat(11.3f, f) == "11");
2047         assert(printFloat(11.0f, f) == "11");
2048         assert(printFloat(-11.5f, f) == "-12");
2049         assert(printFloat(-12.5f, f) == "-13");
2050         assert(printFloat(-11.7f, f) == "-12");
2051         assert(printFloat(-11.3f, f) == "-12");
2052         assert(printFloat(-11.0f, f) == "-11");
2053     }
2054 }
2055 
2056 @safe unittest
2057 {
2058     auto f = FormatSpec!dchar("");
2059     f.spec = 'f';
2060     assert(printFloat(double.nan, f) == "nan");
2061     assert(printFloat(-double.nan, f) == "-nan");
2062     assert(printFloat(double.infinity, f) == "inf");
2063     assert(printFloat(-double.infinity, f) == "-inf");
2064     assert(printFloat(0.0, f) == "0.000000");
2065     assert(printFloat(-0.0, f) == "-0.000000");
2066     // / 1000 needed due to https://issues.dlang.org/show_bug.cgi?id=20361
2067     assert(printFloat(1e-307 / 1000, f) == "0.000000");
2068     assert(printFloat(-1e-307 / 1000, f) == "-0.000000");
2069     assert(printFloat(1e-30, f) == "0.000000");
2070     assert(printFloat(-1e-30, f) == "-0.000000");
2071     assert(printFloat(1e-10, f) == "0.000000");
2072     assert(printFloat(-1e-10, f) == "-0.000000");
2073     assert(printFloat(0.1, f) == "0.100000");
2074     assert(printFloat(-0.1, f) == "-0.100000");
2075     assert(printFloat(10.0, f) == "10.000000");
2076     assert(printFloat(-10.0, f) == "-10.000000");
2077     assert(printFloat(1e300, f) ==
2078            "100000000000000005250476025520442024870446858110815915491585411551180245798890819578637137508044786"
2079           ~"404370444383288387817694252323536043057564479218478670698284838720092657580373783023379478809005936"
2080           ~"895323497079994508111903896764088007465274278014249457925878882005684283811566947219638686545940054"
2081           ~"0160.000000");
2082     assert(printFloat(-1e300, f) ==
2083            "-100000000000000005250476025520442024870446858110815915491585411551180245798890819578637137508044786"
2084           ~"404370444383288387817694252323536043057564479218478670698284838720092657580373783023379478809005936"
2085           ~"895323497079994508111903896764088007465274278014249457925878882005684283811566947219638686545940054"
2086           ~"0160.000000");
2087 
2088     import std.math.operations : nextUp, nextDown;
2089     assert(printFloat(nextUp(0.0), f) == "0.000000");
2090     assert(printFloat(nextDown(-0.0), f) == "-0.000000");
2091 }
2092 
2093 @safe unittest
2094 {
2095     static if (real.mant_dig > 64)
2096     {
2097         pragma(msg, "printFloat tests disabled because of unsupported `real` format");
2098     }
2099     else
2100     {
2101         auto f = FormatSpec!dchar("");
2102         f.spec = 'f';
2103         assert(printFloat(real.nan, f) == "nan");
2104         assert(printFloat(-real.nan, f) == "-nan");
2105         assert(printFloat(real.infinity, f) == "inf");
2106         assert(printFloat(-real.infinity, f) == "-inf");
2107         assert(printFloat(0.0L, f) == "0.000000");
2108         assert(printFloat(-0.0L, f) == "-0.000000");
2109     }
2110 
2111     static if (real.mant_dig == 64)
2112     {
2113         assert(printFloat(1e-4940L, f) == "0.000000");
2114         assert(printFloat(-1e-4940L, f) == "-0.000000");
2115         assert(printFloat(1e-30L, f) == "0.000000");
2116         assert(printFloat(-1e-30L, f) == "-0.000000");
2117         assert(printFloat(1e-10L, f) == "0.000000");
2118         assert(printFloat(-1e-10L, f) == "-0.000000");
2119         assert(printFloat(0.1L, f) == "0.100000");
2120         assert(printFloat(-0.1L, f) == "-0.100000");
2121         assert(printFloat(10.0L, f) == "10.000000");
2122         assert(printFloat(-10.0L, f) == "-10.000000");
version(Windows)2123         version (Windows) {} // issue 20972
2124         else
2125         {
2126             auto result1 = printFloat(1e4000L, f);
2127             assert(result1.length == 4007 && result1[0 .. 40] == "9999999999999999999965463873099623784932");
2128             auto result2 = printFloat(-1e4000L, f);
2129             assert(result2.length == 4008 && result2[0 .. 40] == "-999999999999999999996546387309962378493");
2130         }
2131 
2132         import std.math.operations : nextUp, nextDown;
2133         assert(printFloat(nextUp(0.0L), f) == "0.000000");
2134         assert(printFloat(nextDown(-0.0L), f) == "-0.000000");
2135     }
2136 }
2137 
2138 @safe unittest
2139 {
2140     import std.exception : assertCTFEable;
2141     import std.math.exponential : log2;
2142     import std.math.operations : nextDown;
2143 
2144     assertCTFEable!(
2145     {
2146         // log2 is broken for x87-reals on some computers in CTFE
2147         // the following tests excludes these computers from the tests
2148         // (issue 21757)
2149         enum test = cast(int) log2(3.05e2312L);
2150         static if (real.mant_dig == 64 && test == 7681)
2151         {
2152             auto f = FormatSpec!dchar("");
2153             f.spec = 'f';
2154             assert(printFloat(real.infinity, f) == "inf");
2155             assert(printFloat(10.0L, f) == "10.000000");
2156             assert(printFloat(2.6080L, f) == "2.608000");
2157             auto result1 = printFloat(3.05e2312L, f);
2158             assert(result1.length == 2320);
2159             assert(result1[0 .. 20] == "30499999999999999999");
2160 
2161             f.precision = 60;
2162             assert(printFloat(2.65e-54L, f) ==
2163                    "0.000000000000000000000000000000000000000000000000000002650000");
2164 
2165             /*
2166              commented out, because CTFE is currently too slow for 5000 digits with extreme values
2167 
2168             f.precision = 5000;
2169             auto result2 = printFloat(1.2119e-4822L, f);
2170             assert(result2.length == 5002);
2171             assert(result2[$ - 20 .. $] == "60076763752233836613");
2172             auto result3 = printFloat(real.min_normal, f);
2173             assert(result3.length == 5002);
2174             assert(result3[$ - 20 .. $] == "47124010882722980874");
2175             auto result4 = printFloat(real.min_normal.nextDown, f);
2176             assert(result4.length == 5002);
2177             assert(result4[$ - 20 .. $] == "52925846892214823939");
2178              */
2179         }
2180     });
2181 }
2182 
2183 @safe unittest
2184 {
2185     auto f = FormatSpec!dchar("");
2186     f.spec = 'f';
2187 
2188     import std.math.operations : nextUp;
2189 
2190     double eps = nextUp(0.0);
2191     f.precision = 1000;
2192     assert(printFloat(eps, f) ==
2193            "0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
2194            ~"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
2195            ~"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
2196            ~"00000000000000000000000000000049406564584124654417656879286822137236505980261432476442558568250067"
2197            ~"55072702087518652998363616359923797965646954457177309266567103559397963987747960107818781263007131"
2198            ~"90311404527845817167848982103688718636056998730723050006387409153564984387312473397273169615140031"
2199            ~"71538539807412623856559117102665855668676818703956031062493194527159149245532930545654440112748012"
2200            ~"97099995419319894090804165633245247571478690147267801593552386115501348035264934720193790268107107"
2201            ~"49170333222684475333572083243193609238289345836806010601150616980975307834227731832924790498252473"
2202            ~"07763759272478746560847782037344696995336470179726777175851256605511991315048911014510378627381672"
2203            ~"509558373897335989937");
2204 
2205     f.precision = 0;
2206     assert(printFloat(double.max, f) ==
2207            "179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878"
2208            ~"17154045895351438246423432132688946418276846754670353751698604991057655128207624549009038932894407"
2209            ~"58685084551339423045832369032229481658085593321233482747978262041447231687381771809192998812504040"
2210            ~"26184124858368");
2211 
2212     f.precision = 50;
2213     assert(printFloat(double.epsilon, f) ==
2214            "0.00000000000000022204460492503130808472633361816406");
2215 
2216     f.precision = 10;
2217     assert(printFloat(1.0/3.0, f) == "0.3333333333");
2218     assert(printFloat(1.0/7.0, f) == "0.1428571429");
2219     assert(printFloat(1.0/9.0, f) == "0.1111111111");
2220 }
2221 
2222 @safe unittest
2223 {
2224     auto f = FormatSpec!dchar("");
2225     f.spec = 'f';
2226     f.precision = 15;
2227 
2228     import std.math.constants : E, PI, PI_2, PI_4, M_1_PI, M_2_PI, M_2_SQRTPI,
2229                                 LN10, LN2, LOG2, LOG2E, LOG2T, LOG10E, SQRT2, SQRT1_2;
2230 
2231     assert(printFloat(cast(double) E, f) == "2.718281828459045");
2232     assert(printFloat(cast(double) PI, f) == "3.141592653589793");
2233     assert(printFloat(cast(double) PI_2, f) == "1.570796326794897");
2234     assert(printFloat(cast(double) PI_4, f) == "0.785398163397448");
2235     assert(printFloat(cast(double) M_1_PI, f) == "0.318309886183791");
2236     assert(printFloat(cast(double) M_2_PI, f) == "0.636619772367581");
2237     assert(printFloat(cast(double) M_2_SQRTPI, f) == "1.128379167095513");
2238     assert(printFloat(cast(double) LN10, f) == "2.302585092994046");
2239     assert(printFloat(cast(double) LN2, f) == "0.693147180559945");
2240     assert(printFloat(cast(double) LOG2, f) == "0.301029995663981");
2241     assert(printFloat(cast(double) LOG2E, f) == "1.442695040888963");
2242     assert(printFloat(cast(double) LOG2T, f) == "3.321928094887362");
2243     assert(printFloat(cast(double) LOG10E, f) == "0.434294481903252");
2244     assert(printFloat(cast(double) SQRT2, f) == "1.414213562373095");
2245     assert(printFloat(cast(double) SQRT1_2, f) == "0.707106781186548");
2246 }
2247 
2248 // for 100% coverage
2249 @safe unittest
2250 {
2251     auto f = FormatSpec!dchar("");
2252     f.spec = 'f';
2253     f.precision = 1;
2254     assert(printFloat(9.99, f) == "10.0");
2255 
2256     import std.math.operations : nextUp;
2257 
2258     float eps = nextUp(0.0f);
2259 
2260     f.precision = 148;
2261     assert(printFloat(eps, f) ==
2262            "0.0000000000000000000000000000000000000000000014012984643248170709237295832899161312802619418765157"
2263            ~"717570682838897910826858606014866381883621215820312");
2264 
2265     f.precision = 149;
2266     assert(printFloat(eps, f) ==
2267            "0.0000000000000000000000000000000000000000000014012984643248170709237295832899161312802619418765157"
2268            ~"7175706828388979108268586060148663818836212158203125");
2269 }
2270 
2271 private void printFloatG(Writer, T, Char)(auto ref Writer w, const(T) val,
2272     FormatSpec!Char f, string sgn, int exp, ulong mnt, bool is_upper)
2273 if (is(T == float) || is(T == double)
2274     || (is(T == real) && (T.mant_dig == double.mant_dig || T.mant_dig == 64)))
2275 {
2276     import core.math : abs = fabs;
2277 
2278     if (f.precision == f.UNSPECIFIED)
2279         f.precision = 6;
2280 
2281     if (f.precision == 0)
2282         f.precision = 1;
2283 
2284     import std.math.hardware;
2285     import std.format.internal.write : RoundingMode;
2286 
2287     auto rm = RoundingMode.toNearestTiesToEven;
2288 
2289     if (!__ctfe)
2290     {
2291         // std.math's FloatingPointControl isn't available on all target platforms
2292         static if (is(FloatingPointControl))
2293         {
2294             switch (FloatingPointControl.rounding)
2295             {
2296             case FloatingPointControl.roundUp:
2297                 rm = RoundingMode.up;
2298                 break;
2299             case FloatingPointControl.roundDown:
2300                 rm = RoundingMode.down;
2301                 break;
2302             case FloatingPointControl.roundToZero:
2303                 rm = RoundingMode.toZero;
2304                 break;
2305             case FloatingPointControl.roundToNearest:
2306                 rm = RoundingMode.toNearestTiesToEven;
2307                 break;
2308             default: assert(false, "Unknown floating point rounding mode");
2309             }
2310         }
2311     }
2312 
2313     bool useE = false;
2314 
2315     final switch (rm)
2316     {
2317     case RoundingMode.up:
2318         useE = abs(val) >= 10.0 ^^ f.precision - (val > 0 ? 1 : 0)
2319             || abs(val) < 0.0001 - (val > 0 ? (10.0 ^^ (-4 - f.precision)) : 0);
2320         break;
2321     case RoundingMode.down:
2322         useE = abs(val) >= 10.0 ^^ f.precision - (val < 0 ? 1 : 0)
2323             || abs(val) < 0.0001 - (val < 0 ? (10.0 ^^ (-4 - f.precision)) : 0);
2324         break;
2325     case RoundingMode.toZero:
2326         useE = abs(val) >= 10.0 ^^ f.precision
2327             || abs(val) < 0.0001;
2328         break;
2329     case RoundingMode.toNearestTiesToEven:
2330     case RoundingMode.toNearestTiesAwayFromZero:
2331         useE = abs(val) >= 10.0 ^^ f.precision - 0.5
2332             || abs(val) < 0.0001 - 0.5 * (10.0 ^^ (-4 - f.precision));
2333         break;
2334     }
2335 
2336     if (useE)
2337         return printFloatE!true(w, val, f, sgn, exp, mnt, is_upper);
2338     else
2339         return printFloatF!true(w, val, f, sgn, exp, mnt, is_upper);
2340 }
2341 
2342 @safe unittest
2343 {
2344     // This one tests the switch between e-like and f-like output.
2345     // There is a small gap left between the two, where the used
2346     // variation is not clearly defined. This is intentional and due
2347     // to the way, D handles floating point numbers. On different
2348     // computers with different reals the results may vary in this gap.
2349 
2350     import std.math.operations : nextDown, nextUp;
2351     import std.math.hardware; // cannot be selective, because FloatingPointControl might not be defined
2352 
2353     auto f = FormatSpec!dchar("");
2354     f.spec = 'g';
2355 
2356     double val = 999999.5;
2357     assert(printFloat(val.nextUp, f) == "1e+06");
2358     val = nextDown(val);
2359     assert(printFloat(val.nextDown, f) == "999999");
2360 
2361     val = 0.00009999995;
2362     assert(printFloat(val.nextUp, f) == "0.0001");
2363     val = nextDown(val);
2364     assert(printFloat(val.nextDown, f) == "9.99999e-05");
2365 
2366     static if (is(FloatingPointControl))
2367     {
2368         FloatingPointControl fpctrl;
2369 
2370         fpctrl.rounding = FloatingPointControl.roundToZero;
2371 
2372         val = 1000000;
2373         assert(printFloat(val.nextUp, f) == "1e+06");
2374         val = nextDown(val);
2375         assert(printFloat(val.nextDown, f) == "999999");
2376 
2377         val = 0.0001;
2378         assert(printFloat(val.nextUp, f) == "0.0001");
2379         val = nextDown(val);
2380         assert(printFloat(val.nextDown, f) == "9.99999e-05");
2381 
2382         fpctrl.rounding = FloatingPointControl.roundUp;
2383 
2384         val = 999999;
2385         assert(printFloat(val.nextUp, f) == "1e+06");
2386         val = nextDown(val);
2387         assert(printFloat(val.nextDown, f) == "999999");
2388 
2389         // 0.0000999999 is actually represented as 0.0000999998999..., which is
2390         // less than 0.0000999999, so we need to use nextUp to get the corner case here
2391         val = nextUp(0.0000999999);
2392         assert(printFloat(val.nextUp, f) == "0.0001");
2393         val = nextDown(val);
2394         assert(printFloat(val.nextDown, f) == "9.99999e-05");
2395 
2396         fpctrl.rounding = FloatingPointControl.roundDown;
2397 
2398         val = 1000000;
2399         assert(printFloat(val.nextUp, f) == "1e+06");
2400         val = nextDown(val);
2401         assert(printFloat(val.nextDown, f) == "999999");
2402 
2403         val = 0.0001;
2404         assert(printFloat(val.nextUp, f) == "0.0001");
2405         val = nextDown(val);
2406         assert(printFloat(val.nextDown, f) == "9.99999e-05");
2407     }
2408 }
2409 
2410 @safe unittest
2411 {
2412     auto f = FormatSpec!dchar("");
2413     f.spec = 'g';
2414     assert(printFloat(float.nan, f) == "nan");
2415     assert(printFloat(-float.nan, f) == "-nan");
2416     assert(printFloat(float.infinity, f) == "inf");
2417     assert(printFloat(-float.infinity, f) == "-inf");
2418     assert(printFloat(0.0f, f) == "0");
2419     assert(printFloat(-0.0f, f) == "-0");
2420 
2421     // cast needed due to https://issues.dlang.org/show_bug.cgi?id=20361
2422     assert(printFloat(cast(float) 1e-40, f) == "9.99995e-41");
2423     assert(printFloat(cast(float) -1e-40, f) == "-9.99995e-41");
2424     assert(printFloat(1e-30f, f) == "1e-30");
2425     assert(printFloat(-1e-30f, f) == "-1e-30");
2426     assert(printFloat(1e-10f, f) == "1e-10");
2427     assert(printFloat(-1e-10f, f) == "-1e-10");
2428     assert(printFloat(0.1f, f) == "0.1");
2429     assert(printFloat(-0.1f, f) == "-0.1");
2430     assert(printFloat(10.0f, f) == "10");
2431     assert(printFloat(-10.0f, f) == "-10");
2432     assert(printFloat(1e30f, f) == "1e+30");
2433     assert(printFloat(-1e30f, f) == "-1e+30");
2434 
2435     import std.math.operations : nextUp, nextDown;
2436     assert(printFloat(nextUp(0.0f), f) == "1.4013e-45");
2437     assert(printFloat(nextDown(-0.0f), f) == "-1.4013e-45");
2438 }
2439 
2440 @safe unittest
2441 {
2442     auto f = FormatSpec!dchar("");
2443     f.spec = 'g';
2444     f.width = 20;
2445     f.precision = 10;
2446 
2447     assert(printFloat(float.nan, f) == "                 nan");
2448     assert(printFloat(-float.nan, f) == "                -nan");
2449     assert(printFloat(float.infinity, f) == "                 inf");
2450     assert(printFloat(-float.infinity, f) == "                -inf");
2451     assert(printFloat(0.0f, f) == "                   0");
2452     assert(printFloat(-0.0f, f) == "                  -0");
2453     // cast needed due to https://issues.dlang.org/show_bug.cgi?id=20361
2454     assert(printFloat(cast(float) 1e-40, f) == "     9.999946101e-41");
2455     assert(printFloat(cast(float) -1e-40, f) == "    -9.999946101e-41");
2456     assert(printFloat(1e-30f, f) == "     1.000000003e-30");
2457     assert(printFloat(-1e-30f, f) == "    -1.000000003e-30");
2458     assert(printFloat(1e-10f, f) == "     1.000000013e-10");
2459     assert(printFloat(-1e-10f, f) == "    -1.000000013e-10");
2460     assert(printFloat(0.1f, f) == "        0.1000000015");
2461     assert(printFloat(-0.1f, f) == "       -0.1000000015");
2462     assert(printFloat(10.0f, f) == "                  10");
2463     assert(printFloat(-10.0f, f) == "                 -10");
2464     assert(printFloat(1e30f, f) == "     1.000000015e+30");
2465     assert(printFloat(-1e30f, f) == "    -1.000000015e+30");
2466 
2467     import std.math.operations : nextUp, nextDown;
2468     assert(printFloat(nextUp(0.0f), f) == "     1.401298464e-45");
2469     assert(printFloat(nextDown(-0.0f), f) == "    -1.401298464e-45");
2470 }
2471 
2472 @safe unittest
2473 {
2474     auto f = FormatSpec!dchar("");
2475     f.spec = 'g';
2476     f.width = 20;
2477     f.precision = 10;
2478     f.flDash = true;
2479 
2480     assert(printFloat(float.nan, f) == "nan                 ");
2481     assert(printFloat(-float.nan, f) == "-nan                ");
2482     assert(printFloat(float.infinity, f) == "inf                 ");
2483     assert(printFloat(-float.infinity, f) == "-inf                ");
2484     assert(printFloat(0.0f, f) == "0                   ");
2485     assert(printFloat(-0.0f, f) == "-0                  ");
2486 
2487     // cast needed due to https://issues.dlang.org/show_bug.cgi?id=20361
2488     assert(printFloat(cast(float) 1e-40, f) == "9.999946101e-41     ");
2489     assert(printFloat(cast(float) -1e-40, f) == "-9.999946101e-41    ");
2490     assert(printFloat(1e-30f, f) == "1.000000003e-30     ");
2491     assert(printFloat(-1e-30f, f) == "-1.000000003e-30    ");
2492     assert(printFloat(1e-10f, f) == "1.000000013e-10     ");
2493     assert(printFloat(-1e-10f, f) == "-1.000000013e-10    ");
2494     assert(printFloat(0.1f, f) == "0.1000000015        ");
2495     assert(printFloat(-0.1f, f) == "-0.1000000015       ");
2496     assert(printFloat(10.0f, f) == "10                  ");
2497     assert(printFloat(-10.0f, f) == "-10                 ");
2498     assert(printFloat(1e30f, f) == "1.000000015e+30     ");
2499     assert(printFloat(-1e30f, f) == "-1.000000015e+30    ");
2500 
2501     import std.math.operations : nextUp, nextDown;
2502     assert(printFloat(nextUp(0.0f), f) == "1.401298464e-45     ");
2503     assert(printFloat(nextDown(-0.0f), f) == "-1.401298464e-45    ");
2504 }
2505 
2506 @safe unittest
2507 {
2508     auto f = FormatSpec!dchar("");
2509     f.spec = 'g';
2510     f.width = 20;
2511     f.precision = 10;
2512     f.flZero = true;
2513 
2514     assert(printFloat(float.nan, f) == "                 nan");
2515     assert(printFloat(-float.nan, f) == "                -nan");
2516     assert(printFloat(float.infinity, f) == "                 inf");
2517     assert(printFloat(-float.infinity, f) == "                -inf");
2518     assert(printFloat(0.0f, f) == "00000000000000000000");
2519     assert(printFloat(-0.0f, f) == "-0000000000000000000");
2520 
2521     // cast needed due to https://issues.dlang.org/show_bug.cgi?id=20361
2522     assert(printFloat(cast(float) 1e-40, f) == "000009.999946101e-41");
2523     assert(printFloat(cast(float) -1e-40, f) == "-00009.999946101e-41");
2524     assert(printFloat(1e-30f, f) == "000001.000000003e-30");
2525     assert(printFloat(-1e-30f, f) == "-00001.000000003e-30");
2526     assert(printFloat(1e-10f, f) == "000001.000000013e-10");
2527     assert(printFloat(-1e-10f, f) == "-00001.000000013e-10");
2528     assert(printFloat(0.1f, f) == "000000000.1000000015");
2529     assert(printFloat(-0.1f, f) == "-00000000.1000000015");
2530     assert(printFloat(10.0f, f) == "00000000000000000010");
2531     assert(printFloat(-10.0f, f) == "-0000000000000000010");
2532     assert(printFloat(1e30f, f) == "000001.000000015e+30");
2533     assert(printFloat(-1e30f, f) == "-00001.000000015e+30");
2534 
2535     import std.math.operations : nextUp, nextDown;
2536     assert(printFloat(nextUp(0.0f), f) == "000001.401298464e-45");
2537     assert(printFloat(nextDown(-0.0f), f) == "-00001.401298464e-45");
2538 }
2539 
2540 @safe unittest
2541 {
2542     auto f = FormatSpec!dchar("");
2543     f.spec = 'g';
2544     f.precision = 10;
2545     f.flHash = true;
2546 
2547     assert(printFloat(float.nan, f) == "nan");
2548     assert(printFloat(-float.nan, f) == "-nan");
2549     assert(printFloat(float.infinity, f) == "inf");
2550     assert(printFloat(-float.infinity, f) == "-inf");
2551     assert(printFloat(0.0f, f) == "0.000000000");
2552     assert(printFloat(-0.0f, f) == "-0.000000000");
2553 
2554     // cast needed due to https://issues.dlang.org/show_bug.cgi?id=20361
2555     assert(printFloat(cast(float) 1e-40, f) == "9.999946101e-41");
2556     assert(printFloat(cast(float) -1e-40, f) == "-9.999946101e-41");
2557     assert(printFloat(1e-30f, f) == "1.000000003e-30");
2558     assert(printFloat(-1e-30f, f) == "-1.000000003e-30");
2559     assert(printFloat(1e-10f, f) == "1.000000013e-10");
2560     assert(printFloat(-1e-10f, f) == "-1.000000013e-10");
2561     assert(printFloat(0.1f, f) == "0.1000000015");
2562     assert(printFloat(-0.1f, f) == "-0.1000000015");
2563     assert(printFloat(10.0f, f) == "10.00000000");
2564     assert(printFloat(-10.0f, f) == "-10.00000000");
2565     assert(printFloat(1e30f, f) == "1.000000015e+30");
2566     assert(printFloat(-1e30f, f) == "-1.000000015e+30");
2567 
2568     import std.math.operations : nextUp, nextDown;
2569     assert(printFloat(nextUp(0.0f), f) == "1.401298464e-45");
2570     assert(printFloat(nextDown(-0.0f), f) == "-1.401298464e-45");
2571 }
2572 
2573 @safe unittest
2574 {
2575     import std.math.hardware; // cannot be selective, because FloatingPointControl might not be defined
2576 
2577     // std.math's FloatingPointControl isn't available on all target platforms
2578     static if (is(FloatingPointControl))
2579     {
2580         FloatingPointControl fpctrl;
2581 
2582         char[256] buf;
2583         auto f = FormatSpec!dchar("");
2584         f.spec = 'g';
2585         f.precision = 2;
2586 
2587         fpctrl.rounding = FloatingPointControl.roundToNearest;
2588 
2589         /*
2590          assert(printFloat(11.5f, f, RoundingMode.toNearestTiesAwayFromZero) == "12");
2591          assert(printFloat(12.5f, f, RoundingMode.toNearestTiesAwayFromZero) == "13");
2592          assert(printFloat(11.7f, f, RoundingMode.toNearestTiesAwayFromZero) == "12");
2593          assert(printFloat(11.3f, f, RoundingMode.toNearestTiesAwayFromZero) == "11");
2594          assert(printFloat(11.0f, f, RoundingMode.toNearestTiesAwayFromZero) == "11");
2595          assert(printFloat(-11.5f, f, RoundingMode.toNearestTiesAwayFromZero) == "-12");
2596          assert(printFloat(-12.5f, f, RoundingMode.toNearestTiesAwayFromZero) == "-13");
2597          assert(printFloat(-11.7f, f, RoundingMode.toNearestTiesAwayFromZero) == "-12");
2598          assert(printFloat(-11.3f, f, RoundingMode.toNearestTiesAwayFromZero) == "-11");
2599          assert(printFloat(-11.0f, f, RoundingMode.toNearestTiesAwayFromZero) == "-11");
2600          */
2601 
2602         // ties to even
2603         assert(printFloat(11.5f, f) == "12");
2604         assert(printFloat(12.5f, f) == "12");
2605         assert(printFloat(11.7f, f) == "12");
2606         assert(printFloat(11.3f, f) == "11");
2607         assert(printFloat(11.0f, f) == "11");
2608         assert(printFloat(-11.5f, f) == "-12");
2609         assert(printFloat(-12.5f, f) == "-12");
2610         assert(printFloat(-11.7f, f) == "-12");
2611         assert(printFloat(-11.3f, f) == "-11");
2612         assert(printFloat(-11.0f, f) == "-11");
2613 
2614         fpctrl.rounding = FloatingPointControl.roundToZero;
2615 
2616         assert(printFloat(11.5f, f) == "11");
2617         assert(printFloat(12.5f, f) == "12");
2618         assert(printFloat(11.7f, f) == "11");
2619         assert(printFloat(11.3f, f) == "11");
2620         assert(printFloat(11.0f, f) == "11");
2621         assert(printFloat(-11.5f, f) == "-11");
2622         assert(printFloat(-12.5f, f) == "-12");
2623         assert(printFloat(-11.7f, f) == "-11");
2624         assert(printFloat(-11.3f, f) == "-11");
2625         assert(printFloat(-11.0f, f) == "-11");
2626 
2627         fpctrl.rounding = FloatingPointControl.roundUp;
2628 
2629         assert(printFloat(11.5f, f) == "12");
2630         assert(printFloat(12.5f, f) == "13");
2631         assert(printFloat(11.7f, f) == "12");
2632         assert(printFloat(11.3f, f) == "12");
2633         assert(printFloat(11.0f, f) == "11");
2634         assert(printFloat(-11.5f, f) == "-11");
2635         assert(printFloat(-12.5f, f) == "-12");
2636         assert(printFloat(-11.7f, f) == "-11");
2637         assert(printFloat(-11.3f, f) == "-11");
2638         assert(printFloat(-11.0f, f) == "-11");
2639 
2640         fpctrl.rounding = FloatingPointControl.roundDown;
2641 
2642         assert(printFloat(11.5f, f) == "11");
2643         assert(printFloat(12.5f, f) == "12");
2644         assert(printFloat(11.7f, f) == "11");
2645         assert(printFloat(11.3f, f) == "11");
2646         assert(printFloat(11.0f, f) == "11");
2647         assert(printFloat(-11.5f, f) == "-12");
2648         assert(printFloat(-12.5f, f) == "-13");
2649         assert(printFloat(-11.7f, f) == "-12");
2650         assert(printFloat(-11.3f, f) == "-12");
2651         assert(printFloat(-11.0f, f) == "-11");
2652     }
2653 }
2654 
2655 @safe unittest
2656 {
2657     auto f = FormatSpec!dchar("");
2658     f.spec = 'g';
2659 
2660     assert(printFloat(double.nan, f) == "nan");
2661     assert(printFloat(-double.nan, f) == "-nan");
2662     assert(printFloat(double.infinity, f) == "inf");
2663     assert(printFloat(-double.infinity, f) == "-inf");
2664     assert(printFloat(0.0, f) == "0");
2665     assert(printFloat(-0.0, f) == "-0");
2666 
2667     // / 1000 needed due to https://issues.dlang.org/show_bug.cgi?id=20361
2668     assert(printFloat(1e-307 / 1000, f) == "1e-310");
2669     assert(printFloat(-1e-307 / 1000, f) == "-1e-310");
2670     assert(printFloat(1e-30, f) == "1e-30");
2671     assert(printFloat(-1e-30, f) == "-1e-30");
2672     assert(printFloat(1e-10, f) == "1e-10");
2673     assert(printFloat(-1e-10, f) == "-1e-10");
2674     assert(printFloat(0.1, f) == "0.1");
2675     assert(printFloat(-0.1, f) == "-0.1");
2676     assert(printFloat(10.0, f) == "10");
2677     assert(printFloat(-10.0, f) == "-10");
2678     assert(printFloat(1e300, f) == "1e+300");
2679     assert(printFloat(-1e300, f) == "-1e+300");
2680 
2681     import std.math.operations : nextUp, nextDown;
2682     assert(printFloat(nextUp(0.0), f) == "4.94066e-324");
2683     assert(printFloat(nextDown(-0.0), f) == "-4.94066e-324");
2684 }
2685 
2686 @safe unittest
2687 {
2688     static if (real.mant_dig > 64)
2689     {
2690         pragma(msg, "printFloat tests disabled because of unsupported `real` format");
2691     }
2692     else
2693     {
2694         char[256] buf;
2695         auto f = FormatSpec!dchar("");
2696         f.spec = 'g';
2697 
2698         assert(printFloat(real.nan, f) == "nan");
2699         assert(printFloat(-real.nan, f) == "-nan");
2700         assert(printFloat(real.infinity, f) == "inf");
2701         assert(printFloat(-real.infinity, f) == "-inf");
2702     }
2703 }
2704 
2705 @safe unittest
2706 {
2707     auto f = FormatSpec!dchar("");
2708     f.spec = 'g';
2709 
2710     import std.math.operations : nextUp;
2711 
2712     double eps = nextUp(0.0);
2713     f.precision = 1000;
2714     assert(printFloat(eps, f) ==
2715            "4.940656458412465441765687928682213723650598026143247644255856825006"
2716            ~ "755072702087518652998363616359923797965646954457177309266567103559"
2717            ~ "397963987747960107818781263007131903114045278458171678489821036887"
2718            ~ "186360569987307230500063874091535649843873124733972731696151400317"
2719            ~ "153853980741262385655911710266585566867681870395603106249319452715"
2720            ~ "914924553293054565444011274801297099995419319894090804165633245247"
2721            ~ "571478690147267801593552386115501348035264934720193790268107107491"
2722            ~ "703332226844753335720832431936092382893458368060106011506169809753"
2723            ~ "078342277318329247904982524730776375927247874656084778203734469699"
2724            ~ "533647017972677717585125660551199131504891101451037862738167250955"
2725            ~ "837389733598993664809941164205702637090279242767544565229087538682"
2726            ~ "506419718265533447265625e-324");
2727 
2728     f.precision = 50;
2729     assert(printFloat(double.max, f) ==
2730            "1.7976931348623157081452742373170435679807056752584e+308");
2731     assert(printFloat(double.epsilon, f) ==
2732            "2.220446049250313080847263336181640625e-16");
2733 
2734     f.precision = 10;
2735     assert(printFloat(1.0/3.0, f) == "0.3333333333");
2736     assert(printFloat(1.0/7.0, f) == "0.1428571429");
2737     assert(printFloat(1.0/9.0, f) == "0.1111111111");
2738 }
2739 
2740 @safe unittest
2741 {
2742     auto f = FormatSpec!dchar("");
2743     f.spec = 'g';
2744     f.precision = 15;
2745 
2746     import std.math.constants : E, PI, PI_2, PI_4, M_1_PI, M_2_PI, M_2_SQRTPI,
2747                                 LN10, LN2, LOG2, LOG2E, LOG2T, LOG10E, SQRT2, SQRT1_2;
2748 
2749     assert(printFloat(cast(double) E, f) == "2.71828182845905");
2750     assert(printFloat(cast(double) PI, f) == "3.14159265358979");
2751     assert(printFloat(cast(double) PI_2, f) == "1.5707963267949");
2752     assert(printFloat(cast(double) PI_4, f) == "0.785398163397448");
2753     assert(printFloat(cast(double) M_1_PI, f) == "0.318309886183791");
2754     assert(printFloat(cast(double) M_2_PI, f) == "0.636619772367581");
2755     assert(printFloat(cast(double) M_2_SQRTPI, f) == "1.12837916709551");
2756     assert(printFloat(cast(double) LN10, f) == "2.30258509299405");
2757     assert(printFloat(cast(double) LN2, f) == "0.693147180559945");
2758     assert(printFloat(cast(double) LOG2, f) == "0.301029995663981");
2759     assert(printFloat(cast(double) LOG2E, f) == "1.44269504088896");
2760     assert(printFloat(cast(double) LOG2T, f) == "3.32192809488736");
2761     assert(printFloat(cast(double) LOG10E, f) == "0.434294481903252");
2762     assert(printFloat(cast(double) SQRT2, f) == "1.4142135623731");
2763     assert(printFloat(cast(double) SQRT1_2, f) == "0.707106781186548");
2764 }
2765 
2766 // for 100% coverage
2767 @safe unittest
2768 {
2769     auto f = FormatSpec!dchar("");
2770     f.spec = 'g';
2771     f.precision = 0;
2772 
2773     assert(printFloat(0.009999, f) == "0.01");
2774 }
2775 
2776 @safe unittest
2777 {
2778     static if (real.mant_dig > 64)
2779     {
2780         pragma(msg, "printFloat tests disabled because of unsupported `real` format");
2781     }
2782     else
2783     {
2784         auto f = FormatSpec!dchar("");
2785         f.spec = 'g';
2786         assert(printFloat(real.nan, f) == "nan");
2787         assert(printFloat(-real.nan, f) == "-nan");
2788         assert(printFloat(real.infinity, f) == "inf");
2789         assert(printFloat(-real.infinity, f) == "-inf");
2790         assert(printFloat(0.0L, f) == "0");
2791         assert(printFloat(-0.0L, f) == "-0");
2792     }
2793 
2794     static if (real.mant_dig == 64)
2795     {
2796         assert(printFloat(1e-4940L, f) == "1e-4940");
2797         assert(printFloat(-1e-4940L, f) == "-1e-4940");
2798         assert(printFloat(1e-30L, f) == "1e-30");
2799         assert(printFloat(-1e-30L, f) == "-1e-30");
2800         assert(printFloat(1e-10L, f) == "1e-10");
2801         assert(printFloat(-1e-10L, f) == "-1e-10");
2802         assert(printFloat(0.1L, f) == "0.1");
2803         assert(printFloat(-0.1L, f) == "-0.1");
2804         assert(printFloat(10.0L, f) == "10");
2805         assert(printFloat(-10.0L, f) == "-10");
version(Windows)2806         version (Windows) {} // issue 20972
2807         else
2808         {
2809             assert(printFloat(1e4000L, f) == "1e+4000");
2810             assert(printFloat(-1e4000L, f) == "-1e+4000");
2811         }
2812 
2813         import std.math.operations : nextUp, nextDown;
2814         assert(printFloat(nextUp(0.0L), f) == "3.6452e-4951");
2815         assert(printFloat(nextDown(-0.0L), f) == "-3.6452e-4951");
2816     }
2817 }
2818 
2819 @safe unittest
2820 {
2821     import std.exception : assertCTFEable;
2822     import std.math.exponential : log2;
2823     import std.math.operations : nextDown;
2824 
2825     assertCTFEable!(
2826     {
2827         // log2 is broken for x87-reals on some computers in CTFE
2828         // the following tests excludes these computers from the tests
2829         // (issue 21757)
2830         enum test = cast(int) log2(3.05e2312L);
2831         static if (real.mant_dig == 64 && test == 7681)
2832         {
2833             auto f = FormatSpec!dchar("");
2834             f.spec = 'g';
2835             assert(printFloat(real.infinity, f) == "inf");
2836             assert(printFloat(10.0L, f) == "10");
2837             assert(printFloat(2.6080L, f) == "2.608");
2838             assert(printFloat(3.05e2312L, f) == "3.05e+2312");
2839 
2840             f.precision = 60;
2841             assert(printFloat(2.65e-54L, f) ==
2842                    "2.65000000000000000005900998740054701394102894093529654759941e-54");
2843 
2844             /*
2845              commented out, because CTFE is currently too slow for 5000 digits with extreme values
2846 
2847             f.precision = 5000;
2848             auto result2 = printFloat(1.2119e-4822L, f);
2849             assert(result2.length == 5007);
2850             assert(result2[$ - 20 .. $] == "26072948659534e-4822");
2851             auto result3 = printFloat(real.min_normal, f);
2852             assert(result3.length == 5007);
2853             assert(result3[$ - 20 .. $] == "72078141008227e-4932");
2854             auto result4 = printFloat(real.min_normal.nextDown, f);
2855             assert(result4.length == 5007);
2856             assert(result4[$ - 20 .. $] == "48141326333101e-4932");
2857              */
2858         }
2859     });
2860 }
2861 
2862 // check no allocations
2863 @safe unittest
2864 {
2865     import std.format : NoOpSink;
2866     auto w = NoOpSink();
2867 
2868     import core.memory;
2869     auto stats = () @trusted { return GC.stats; } ();
2870 
2871     auto f = FormatSpec!dchar("");
2872     f.spec = 'a';
2873     printFloat(w, float.nan, f);
2874     printFloat(w, -float.infinity, f);
2875     printFloat(w, 0.0f, f);
2876 
2877     printFloat(w, -double.nan, f);
2878     printFloat(w, double.infinity, f);
2879     printFloat(w, -0.0, f);
2880 
2881     import std.math.operations : nextUp;
2882     import std.math.constants : E;
2883 
2884     printFloat(w, nextUp(0.0f), f);
2885     printFloat(w, cast(float) E, f);
2886 
2887     f.precision = 1000;
2888     printFloat(w, float.nan, f);
2889     printFloat(w, 0.0, f);
2890     printFloat(w, 1.23456789e+100, f);
2891 
2892     f.spec = 'E';
2893     f.precision = 80;
2894     printFloat(w, 5.62776e+12f, f);
2895 
2896     f.precision = 6;
2897     printFloat(w, -1.1418613e+07f, f);
2898 
2899     f.precision = 20;
2900     printFloat(w, double.max, f);
2901     printFloat(w, nextUp(0.0), f);
2902 
2903     f.precision = 1000;
2904     printFloat(w, 1.0, f);
2905 
2906     f.spec = 'f';
2907     f.precision = 15;
2908     printFloat(w, cast(double) E, f);
2909 
2910     f.precision = 20;
2911     printFloat(w, double.max, f);
2912     printFloat(w, nextUp(0.0), f);
2913 
2914     f.precision = 1000;
2915     printFloat(w, 1.0, f);
2916 
2917     f.spec = 'g';
2918     f.precision = 15;
2919     printFloat(w, cast(double) E, f);
2920 
2921     f.precision = 20;
2922     printFloat(w, double.max, f);
2923     printFloat(w, nextUp(0.0), f);
2924 
2925     f.flHash = true;
2926     f.precision = 1000;
2927     printFloat(w, 1.0, f);
2928 
2929     assert(() @trusted { return GC.stats.usedSize; } () == stats.usedSize);
2930 }
2931