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
15module std.format.internal.floats;
16
17import std.format.spec : FormatSpec;
18
19// wrapper for unittests
20private auto printFloat(T, Char)(const(T) val, FormatSpec!Char f)
21if (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
31package(std.format) void printFloat(Writer, T, Char)(auto ref Writer w, const(T) val, FormatSpec!Char f)
32if (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
79private 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)
81if (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
589private 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)
591if (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;
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;
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;
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;
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");
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
1508private 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)
1510if (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;
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;
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;
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");
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
2271private 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)
2273if (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");
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