1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 /**
6  * This module provides $(D_PSYMBOL format) function that can convert different
7  * data types to a $(D_PSYMBOL String) according to a specified format.
8  *
9  * Format string is a $(D_PSYMBOL string) which can contain placeholders for
10  * arguments. Placeholder marker is `{}`, i.e. all occurrences of `{}` are
11  * replaced by the arguments passed to $(D_PSYMBOL format). An argument will be
12  * first converted to a string, then inserted into the resulting string instead
13  * of the corresponding placeholder. The number of the placeholders and
14  * arguments must match. The placeholders are replaced with the arguments in
15  * the order arguments are passed to $(D_PSYMBOL format).
16  *
17  * To escape `{` or `}`, use `{{` and `}}` respectively. `{{` will be outputted
18  * as a single `{`, `}}` - as a single `}`.
19  *
20  * To define the string representation for a custom data type (like
21  * $(D_KEYWORD class) or $(D_KEYWORD struct)), `toString()`-function can be
22  * implemented for that type. `toString()` should be $(D_KEYWORD const) and
23  * accept exactly one argument: an output range for `const(char)[]`. It should
24  * return the same output range, advanced after putting the corresponding value
25  * into it. That is `toString()` signature should look like:
26  *
27  * ---
28  * OR toString(OR)(OR range) const
29  * if (isOutputRange!(OR, const(char)[]));
30  * ---
31  *
32  * String conversions for the most built-in data types a also available.
33  *
34  * $(D_KEYWORD char), $(D_KEYWORD wchar) and $(D_KEYWORD dchar) ranges are
35  * outputted as plain strings (without any delimiters between their elements).
36  *
37  * All floating point numbers are handled as $(D_KEYWORD double)s.
38  *
39  * More advanced formatting is currently not implemented.
40  *
41  * Copyright: Eugene Wissner 2017-2022.
42  * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
43  *                  Mozilla Public License, v. 2.0).
44  * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
45  * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/format/package.d,
46  *                 tanya/format/package.d)
47  */
48 module tanya.format;
49 
50 import std.algorithm.comparison;
51 import std.ascii;
52 import tanya.container.string;
53 import tanya.math;
54 static import tanya.memory.op;
55 import tanya.meta.metafunction;
56 import tanya.meta.trait;
57 import tanya.meta.transform;
58 import tanya.range;
59 
60 // Returns the last part of buffer with converted number.
61 package(tanya) char[] integral2String(T)(T number, return ref char[21] buffer)
62 @trusted
63 if (isIntegral!T)
64 {
65     // abs the integer.
66     ulong n64 = number < 0 ? -cast(long) number : number;
67 
68     char* start = buffer[].ptr + buffer.sizeof - 1;
69 
70     while (true)
71     {
72         // Do in 32-bit chunks (avoid lots of 64-bit divides even with constant
73         // denominators).
74         char* o = start - 8;
75         uint n;
76         if (n64 >= 100000000)
77         {
78             n = n64 % 100000000;
79             n64 /= 100000000;
80         }
81         else
82         {
83             n = cast(uint) n64;
84             n64 = 0;
85         }
86 
87         while (n)
88         {
89             *--start = cast(char) (n % 10) + '0';
90             n /= 10;
91         }
92         // Ignore the leading zero if it was the last part of the integer.
93         if (n64 == 0)
94         {
95             if ((start[0] == '0')
96              && (start != (buffer[].ptr + buffer.sizeof -1)))
97             {
98                 ++start;
99             }
100             break;
101         }
102         // Copy leading zeros if it wasn't the most significant part of the
103         // integer.
104         while (start != o)
105         {
106             *--start = '0';
107         }
108     }
109 
110     // Get the length that we have copied.
111     uint l = cast(uint) ((buffer[].ptr + buffer.sizeof - 1) - start);
112     if (l == 0)
113     {
114         *--start = '0';
115         l = 1;
116     }
117     else if (number < 0) // Set the sign.
118     {
119         *--start = '-';
120         ++l;
121     }
122 
123     return buffer[$ - l - 1 .. $ - 1];
124 }
125 
126 private int frexp(const double x) @nogc nothrow pure @safe
127 {
128     const FloatBits!double bits = { x };
129     const int biased = (bits.integral & 0x7fffffffffffffffUL) >> 52;
130 
131     if ((bits.integral << 1) == 0 || biased == 0x7ff) // 0, NaN of Infinity
132     {
133         return 0;
134     }
135     else if (biased == 0) // Subnormal, normalize the exponent
136     {
137         return frexp(x * 0x1p64) - 64;
138     }
139 
140     return biased - 1022;
141 }
142 
143 /*
144  * Double-double high-precision floating point number.
145  *
146  * The first element is a base value corresponding to the nearest approximation
147  * of the target $(D_PSYMBOL HP) value, and the second element is an offset
148  * value corresponding to the difference between the target value and the base.
149  * Thus, the $(D_PSYMBOL HP) value represented is the sum of the base and the
150  * offset.
151  */
152 private struct HP
153 {
154     double base;
155     double offset = 0.0;
156 
157     this(double base, double offset = 0.0) @nogc nothrow pure @safe
158     {
159         this.base = base;
160         this.offset = offset;
161     }
162 
163     void normalize() @nogc nothrow pure @safe
164     {
165         const double target = this.base + this.offset;
166         this.offset -= target - this.base;
167         this.base = target;
168     }
169 
170     void multiplyBy10() @nogc nothrow pure @safe
171     {
172         const double h = 8 * this.base + 2 * this.base;
173         const double l = 10 * this.offset;
174         const double c = (h - 8 * this.base) - 2 * this.base;
175 
176         this.base = h;
177         this.offset = l - c;
178 
179         normalize();
180     }
181 
182     void divideBy10() @nogc nothrow pure @safe
183     {
184         const double h = this.base / 10.0;
185         const double l = this.offset / 10.0;
186         const double c = (this.base - 8.0 * h) - 2.0 * h;
187 
188         this.base = h;
189         this.offset = l + c / 10.0;
190 
191         normalize();
192     }
193 
194     HP opBinary(string op : "*")(const double value) const
195     {
196         HP factor1 = split(this.base);
197         HP factor2 = split(value);
198 
199         const double base = this.base * value;
200         const double offset = (factor1.base * factor2.base - base)
201                             + factor1.base * factor2.offset
202                             + factor1.offset * factor2.base
203                             + factor1.offset * factor2.offset;
204 
205         return HP(base, this.offset * value + offset);
206     }
207 }
208 
209 /*
210  * Splits a double into two FP numbers.
211  */
212 private HP split(double x) @nogc nothrow pure @safe
213 {
214     FloatBits!double bits = { x };
215     bits.integral &= 0xfffffffff8000000UL;
216     return HP(bits.floating , x - bits.floating);
217 }
218 
219 private enum special = 0x7000;
220 private enum char period = '.';
221 
222 // Error factor. Determines the width of the narrow and wide intervals.
223 private enum double epsilon = 8.78e-15;
224 
225 private immutable HP[600] powersOf10 = [
226     HP(1e308, -0x1.c2a3c3d855605p+966),
227     HP(1e307, 0x1.cab0301fbbb2ep+963),
228     HP(1e306, -0x1.c43fd98036a40p+960),
229     HP(1e305, 0x1.3f266e198eabfp+959),
230     HP(1e304, 0x1.fea3e35c17799p+955),
231     HP(1e303, -0x1.167d4fed38558p+944),
232     HP(1e302, -0x1.9a78643ff0f9dp+949),
233     HP(1e301, -0x1.c3f3d399818fcp+945),
234     HP(1e300, -0x1.698fdc7ace0cap+942),
235     HP(1e299, -0x1.213fe39571a3bp+939),
236     HP(1e298, 0x1.646693ddb093ap+935),
237     HP(1e297, -0x1.f1eaf3a0fe277p+930),
238     HP(1e296, 0x1.a4dda37f34ad3p+927),
239     HP(1e295, 0x1.50b14f98f6f0fp+924),
240     HP(1e294, -0x1.dfb9135c6a060p+922),
241     HP(1e293, 0x1.b36bf082de619p+919),
242     HP(1e292, -0x1.ea19fcba70c29p+913),
243     HP(1e291, 0x1.3794670de972ap+912),
244     HP(1e290, -0x1.6d22e0c1aba44p+909),
245     HP(1e289, -0x1.241be701561d0p+906),
246     HP(1e288, -0x1.ce31f3444e400p+899),
247     HP(1e287, -0x1.c7d1cb86d4a00p+899),
248     HP(1e286, -0x1.3fb6127154333p+895),
249     HP(1e285, 0x1.33a97c177947ap+891),
250     HP(1e284, -0x1.eb55ce5d02b02p+889),
251     HP(1e283, 0x1.baa9e904c87fcp+885),
252     HP(1e282, -0x1.0444df2f5f99cp+882),
253     HP(1e281, -0x1.a06e31e565c2dp+878),
254     HP(1e280, -0x1.4d24f4b7849bdp+875),
255     HP(1e279, -0x1.d750c3c603afep+872),
256     HP(1e278, 0x1.dab1f9f660802p+868),
257     HP(1e277, -0x1.dd804d47f9974p+861),
258     HP(1e276, -0x1.b1799d76cc7acp+862),
259     HP(1e275, 0x1.0b9eb53a8f9dcp+859),
260     HP(1e274, 0x1.a2e55dc872e4ap+856),
261     HP(1e273, 0x1.d16efc73eb076p+852),
262     HP(1e272, -0x1.beda693cdd93ap+849),
263     HP(1e271, 0x1.00eadf0281f04p+846),
264     HP(1e270, -0x1.9821ce62634c6p+842),
265     HP(1e269, -0x1.468171e84f704p+839),
266     HP(1e268, 0x1.28ca7cf2b4191p+835),
267     HP(1e267, 0x1.dadd94b7868e9p+831),
268     HP(1e266, -0x1.b74ebc39fac12p+828),
269     HP(1e265, -0x1.7c85e4e3fde6dp+826),
270     HP(1e264, -0x1.94096e39963e2p+822),
271     HP(1e263, -0x1.d9b7c71ead93bp+817),
272     HP(1e262, -0x1.7af96c188adc9p+814),
273     HP(1e261, 0x1.4dce1d94b1071p+813),
274     HP(1e260, -0x1.e9e96a454b27dp+809),
275     HP(1e259, 0x1.ab4544955d79bp+806),
276     HP(1e258, -0x1.109562bbb5383p+803),
277     HP(1e257, -0x1.ceaad58bdd80cp+798),
278     HP(1e256, -0x1.7222446fe4670p+795),
279     HP(1e255, 0x1.c5f8be99f1e99p+790),
280     HP(1e254, 0x1.f464f2eb96c85p+789),
281     HP(1e253, 0x1.9050c2561239dp+786),
282     HP(1e252, -0x1.f2f297bb249e8p+783),
283     HP(1e251, -0x1.84b7592b6dca6p+779),
284     HP(1e250, 0x1.fc3a1f1074f7ap+776),
285     HP(1e249, 0x1.9694e5a6c3f95p+773),
286     HP(1e248, -0x1.75782a28600aap+769),
287     HP(1e247, 0x1.3b9fde4619910p+766),
288     HP(1e246, -0x1.69e6816185258p+763),
289     HP(1e245, -0x1.763d9bcf3b6f4p+759),
290     HP(1e244, -0x1.f831497295f2ap+756),
291     HP(1e243, -0x1.935aa12877f54p+753),
292     HP(1e242, -0x1.b89101da59887p+749),
293     HP(1e241, -0x1.6074017b7ad39p+746),
294     HP(1e240, -0x1.34a66b24bc3eap+741),
295     HP(1e239, 0x1.455c215ed2ceep+737),
296     HP(1e238, -0x1.58872c86a2a36p+736),
297     HP(1e237, 0x1.52c70f944ab07p+733),
298     HP(1e236, -0x1.e1f4b3df887f4p+729),
299     HP(1e235, -0x1.81908fe606cc3p+726),
300     HP(1e234, -0x1.9e9b661348f3dp+721),
301     HP(1e233, 0x1.e783ae56f8d68p+718),
302     HP(1e232, -0x1.a364ed76cfaa3p+716),
303     HP(1e231, -0x1.4f83f12bd954fp+713),
304     HP(1e230, -0x1.d9365a897aaa5p+710),
305     HP(1e229, 0x1.f07b792044482p+703),
306     HP(1e228, 0x1.cb3f8c1cd3a0dp+703),
307     HP(1e227, -0x1.c3cd298289e5bp+700),
308     HP(1e226, 0x1.2d1e23fbf02a0p+696),
309     HP(1e225, 0x1.bdb1b66326880p+693),
310     HP(1e224, 0x1.2f82bd6b70d99p+689),
311     HP(1e223, -0x1.73976876d8eb8p+686),
312     HP(1e222, -0x1.2945ed2be0bc6p+683),
313     HP(1e221, -0x1.dba31513012d7p+679),
314     HP(1e220, 0x1.d172257324207p+672),
315     HP(1e219, 0x1.c82503beb6d00p+672),
316     HP(1e218, -0x1.aff131b3b6dffp+670),
317     HP(1e217, 0x1.4ce47d46db666p+666),
318     HP(1e216, -0x1.1e926ac1d428ep+662),
319     HP(1e215, 0x1.f3c56ee5ab22dp+660),
320     HP(1e214, 0x1.8608b16f7837bp+656),
321     HP(1e213, 0x1.ace89e3180b25p+651),
322     HP(1e212, 0x1.ef61b93d19bd4p+650),
323     HP(1e211, 0x1.7f02c1fb5c620p+646),
324     HP(1e210, 0x1.ff3567fc49e80p+643),
325     HP(1e209, -0x1.9a3baccfc4dffp+640),
326     HP(1e208, 0x1.45a7709a56ccdp+635),
327     HP(1e207, -0x1.17569fc243ae0p+633),
328     HP(1e206, -0x1.bef0ff9d39167p+629),
329     HP(1e205, -0x1.318198fb8e8a5p+625),
330     HP(1e204, 0x1.4a63d8071bef6p+621),
331     HP(1e203, 0x1.084fe005aff2bp+618),
332     HP(1e202, 0x1.ce76600123308p+617),
333     HP(1e201, -0x1.1c0f6664947f2p+613),
334     HP(1e200, 0x1.6cb428f8ac016p+609),
335     HP(1e199, -0x1.d484bc6954cc3p+607),
336     HP(1e198, -0x1.0e758e1ddc272p+602),
337     HP(1e197, 0x1.2d6a93f40e56bp+600),
338     HP(1e196, 0x1.e2441fece3bdfp+596),
339     HP(1e195, 0x1.6a06997b05fccp+592),
340     HP(1e194, 0x1.5d9c3d6468cb8p+590),
341     HP(1e193, -0x1.4eb6354945c39p+587),
342     HP(1e192, -0x1.4abd220ed605cp+583),
343     HP(1e191, -0x1.d5641b3f119e3p+580),
344     HP(1e190, -0x1.778348ff414b5p+577),
345     HP(1e189, -0x1.7e70e99737579p+572),
346     HP(1e188, -0x1.31f3ee1292ac7p+569),
347     HP(1e187, 0x1.ec04d3f892216p+567),
348     HP(1e186, 0x1.59a90cb506d15p+562),
349     HP(1e185, 0x1.14873d5d9f0ddp+559),
350     HP(1e184, -0x1.78c1376a34b69p+555),
351     HP(1e183, 0x1.cfb2b6a251508p+553),
352     HP(1e182, -0x1.c03dd44af225fp+550),
353     HP(1e181, 0x1.cc9b562a717b3p+547),
354     HP(1e180, -0x1.48eaa556c351bp+541),
355     HP(1e179, 0x1.16088aaa1845bp+539),
356     HP(1e178, -0x1.2a62fbbbf64a8p+537),
357     HP(1e177, -0x1.0f464b195b767p+531),
358     HP(1e176, -0x1.b20a11c22bf0cp+527),
359     HP(1e175, 0x1.6e32316c9534bp+527),
360     HP(1e174, -0x1.4171720f88a29p+524),
361     HP(1e173, -0x1.a2d60d303743fp+518),
362     HP(1e172, -0x1.ed5e02a33e40cp+517),
363     HP(1e171, 0x1.b769956135febp+513),
364     HP(1e170, -0x1.06debbb23b343p+510),
365     HP(1e169, 0x1.941a9d0b03d63p+507),
366     HP(1e168, 0x1.43487da269782p+504),
367     HP(1e167, -0x1.2df26a2f573fbp+500),
368     HP(1e166, 0x1.74d7ab0d53cd0p+497),
369     HP(1e165, 0x1.f712ef3ddca40p+494),
370     HP(1e164, -0x1.c9035a0712651p+485),
371     HP(1e163, 0x1.8e2cb7596c571p+487),
372     HP(1e162, 0x1.3e8a2c4789df4p+484),
373     HP(1e161, -0x1.358952c0bd012p+480),
374     HP(1e160, -0x1.56a2119e533acp+474),
375     HP(1e159, 0x1.775631702ae08p+474),
376     HP(1e158, 0x1.8bbd1be6ab00dp+470),
377     HP(1e157, 0x1.bf29f2e22335dp+465),
378     HP(1e156, 0x1.65bb28b4e8f7ep+462),
379     HP(1e155, -0x1.eda91756b019fp+457),
380     HP(1e154, -0x1.fc5504aaf0053p+456),
381     HP(1e153, 0x1.7797bb9ffdecbp+446),
382     HP(1e152, -0x1.9740a6d3ccd01p+450),
383     HP(1e151, -0x1.e40215d8f5cd2p+445),
384     HP(1e150, 0x1.affe54ec0828ap+442),
385     HP(1e149, -0x1.b99a446e6322fp+440),
386     HP(1e148, -0x1.614836beb5b58p+437),
387     HP(1e147, 0x1.fbe5b73754216p+432),
388     HP(1e146, 0x1.326124a4aa6d1p+431),
389     HP(1e145, 0x1.426db7510f86fp+425),
390     HP(1e144, -0x1.18a0e9df93639p+423),
391     HP(1e143, -0x1.c1017632856c2p+419),
392     HP(1e142, -0x1.8066fc14355e7p+417),
393     HP(1e141, -0x1.9ae326a7112e5p+412),
394     HP(1e140, -0x1.1efa3aee36a2dp+411),
395     HP(1e139, -0x1.fcba562d7ba2cp+406),
396     HP(1e138, -0x1.96fb782462e89p+403),
397     HP(1e137, -0x1.4595f9b6b586ep+400),
398     HP(1e136, -0x1.d144c7c55e058p+397),
399     HP(1e135, 0x1.e45ec05dcff72p+393),
400     HP(1e134, 0x1.8e8c4cf2532fap+391),
401     HP(1e133, -0x1.6b0bd69229010p+386),
402     HP(1e132, 0x1.dca6eaf916630p+381),
403     HP(1e131, 0x1.c943e44c1bd6bp+381),
404     HP(1e130, -0x1.f12cf91fd3754p+377),
405     HP(1e129, 0x1.7b80b0047445dp+369),
406     HP(1e128, -0x1.901cc86649e4ap+371),
407     HP(1e127, 0x1.7fd1f28f89c55p+367),
408     HP(1e126, 0x1.ffdb2872d49dep+364),
409     HP(1e125, 0x1.997c205bdd4b1p+361),
410     HP(1e124, 0x1.c26033c62ede9p+357),
411     HP(1e123, 0x1.370052d6b1641p+353),
412     HP(1e122, -0x1.4199150ee42c9p+349),
413     HP(1e121, -0x1.4d706ed2c1ab7p+347),
414     HP(1e120, 0x1.1db281e1fd541p+343),
415     HP(1e119, 0x1.3f1433f3feee6p+341),
416     HP(1e118, 0x1.31b9ecb997e3ep+337),
417     HP(1e117, -0x1.71d1a90520167p+334),
418     HP(1e116, -0x1.6c38834399e18p+329),
419     HP(1e115, -0x1.23606902e1813p+326),
420     HP(1e114, -0x1.d233db37cf353p+322),
421     HP(1e113, -0x1.74f648f97290fp+319),
422     HP(1e112, 0x1.4f01f167b5e30p+318),
423     HP(1e111, 0x1.4b364f0c56380p+314),
424     HP(1e110, -0x1.2142b4b90fa66p+310),
425     HP(1e109, 0x1.6462120b1a28fp+306),
426     HP(1e108, -0x1.0b0bf8c85bef9p+304),
427     HP(1e107, 0x1.87ecd8590680ap+300),
428     HP(1e106, -0x1.c9a1430f96ffbp+298),
429     HP(1e105, 0x1.f09794b3db339p+294),
430     HP(1e104, -0x1.8a712136e13d3p+286),
431     HP(1e103, -0x1.3b8db42be7642p+283),
432     HP(1e102, 0x1.7a0b6dfb9c0f9p+283),
433     HP(1e101, 0x1.2e6f8b2fb00c7p+280),
434     HP(1e100, -0x1.4f4d87b3b31f4p+276),
435     HP(1e99, 0x1.137a9684eb8d1p+274),
436     HP(1e98, 0x1.f2a8a6e45ae8ep+266),
437     HP(1e97, -0x1.8d222f071753cp+268),
438     HP(1e96, -0x1.ae9d180b58860p+264),
439     HP(1e95, -0x1.1761c012273cdp+260),
440     HP(1e94, -0x1.bf02cce9d8616p+256),
441     HP(1e93, -0x1.7f9ab85d89c08p+254),
442     HP(1e92, -0x1.32e22d17a166dp+251),
443     HP(1e91, -0x1.c24e8a794debep+248),
444     HP(1e90, 0x1.2f8255a450203p+244),
445     HP(1e89, 0x1.300ef0e867347p+238),
446     HP(1e88, 0x1.d6696361ae3dbp+237),
447     HP(1e87, 0x1.78544f8158315p+234),
448     HP(1e86, -0x1.b22567fbb2954p+229),
449     HP(1e85, -0x1.5b511ffc8eddcp+226),
450     HP(1e84, -0x1.12436ccc1c92cp+225),
451     HP(1e83, -0x1.d40af5c05b6f3p+220),
452     HP(1e82, 0x1.bcc40832ea0d6p+217),
453     HP(1e81, 0x1.7eb4d0145d9efp+215),
454     HP(1e80, -0x1.08f322e84da10p+204),
455     HP(1e79, 0x1.9649c2c37f079p+207),
456     HP(1e78, -0x1.52472a5b364e1p+202),
457     HP(1e77, 0x1.1249ef0eb713fp+200),
458     HP(1e76, -0x1.2be26d2d505e6p+198),
459     HP(1e75, 0x1.767e0f0ef2e7ap+195),
460     HP(1e74, 0x1.8a634b4b1e3f7p+191),
461     HP(1e73, 0x1.bad75756c7317p+186),
462     HP(1e72, 0x1.255e44aaf4a37p+185),
463     HP(1e71, -0x1.5dcf9221abc73p+181),
464     HP(1e70, -0x1.e4a60e815638fp+178),
465     HP(1e69, -0x1.83b80b9aab60cp+175),
466     HP(1e68, 0x1.93a653d55431fp+171),
467     HP(1e67, 0x1.d87aa5ddda397p+166),
468     HP(1e66, 0x1.2b4bbac5f871ep+165),
469     HP(1e65, 0x1.1517de8c9c728p+159),
470     HP(1e64, -0x1.2ac340948e389p+157),
471     HP(1e63, -0x1.444e19d505b03p+155),
472     HP(1e62, -0x1.3a168fbb3c4d2p+151),
473     HP(1e61, 0x1.6b21269d695bdp+148),
474     HP(1e60, 0x1.2280ebb121164p+145),
475     HP(1e59, 0x1.0401791b6823ap+141),
476     HP(1e58, 0x1.9ccdfa7c534fbp+138),
477     HP(1e57, -0x1.1c28046956f36p+135),
478     HP(1e56, -0x1.b020038778c2bp+132),
479     HP(1e55, -0x1.3400169638117p+126),
480     HP(1e54, -0x1.d73337b7a4d04p+125),
481     HP(1e53, 0x1.051e9b68adfe1p+119),
482     HP(1e52, 0x1.a1ca924116635p+115),
483     HP(1e51, 0x1.4e3ba83411e91p+112),
484     HP(1e50, -0x1.782d3bfacb024p+112),
485     HP(1e49, 0x1.a61e066ebb2f8p+108),
486     HP(1e48, -0x1.14b4c7a76a405p+105),
487     HP(1e47, -0x1.babad90bdd33cp+101),
488     HP(1e46, 0x1.bb542c80deb48p+95),
489     HP(1e45, 0x1.c5eed14016454p+95),
490     HP(1e44, -0x1.c80dbeffee2f0p+92),
491     HP(1e43, -0x1.cd24c665f4600p+86),
492     HP(1e42, -0x1.29075ae130e00p+85),
493     HP(1e41, -0x1.069578d46c000p+79),
494     HP(1e40, -0x1.0151182a7c000p+78),
495     HP(1e39, 0x1.988becaad0000p+75),
496     HP(1e38, 0x1.e826288900000p+70),
497     HP(1e37, 0x1.900f436a00000p+68),
498     HP(1e36, -0x1.265a307800000p+65),
499     HP(1e35, 0x1.5c3c7f4000000p+61),
500     HP(1e34, 0x1.e363990000000p+58),
501     HP(1e33, 0x1.82b6140000000p+55),
502     HP(1e32, -0x1.3107f00000000p+52),
503     HP(1e31, 0x1.4b26800000000p+48),
504     HP(1e30, -0x1.215c000000000p+44),
505     HP(1e29, 0x1.f2a8000000000p+42),
506     HP(1e28, 0x1.8440000000000p+38),
507     HP(1e27, -0x1.8c00000000000p+33),
508     HP(1e26, -0x1.1c00000000000p+32),
509     HP(1e25, -0x1.b000000000000p+29),
510     HP(1e24, 0x1.0000000000000p+24),
511     HP(1e23, 0x1.0000000000000p+23),
512     HP(1e22, 0x0.0000000000000p+0),
513     HP(1e21, 0x0.0000000000000p+0),
514     HP(1e20, 0x0.0000000000000p+0),
515     HP(1e19, 0x0.0000000000000p+0),
516     HP(1e18, 0x0.0000000000000p+0),
517     HP(1e17, 0x0.0000000000000p+0),
518     HP(1e16, 0x0.0000000000000p+0),
519     HP(1e15, 0x0.0000000000000p+0),
520     HP(1e14, 0x0.0000000000000p+0),
521     HP(1e13, 0x0.0000000000000p+0),
522     HP(1e12, 0x0.0000000000000p+0),
523     HP(1e11, 0x0.0000000000000p+0),
524     HP(1e10, 0x0.0000000000000p+0),
525     HP(1e9, 0x0.0000000000000p+0),
526     HP(1e8, 0x0.0000000000000p+0),
527     HP(1e7, 0x0.0000000000000p+0),
528     HP(1e6, 0x0.0000000000000p+0),
529     HP(1e5, 0x0.0000000000000p+0),
530     HP(1e4, 0x0.0000000000000p+0),
531     HP(1e3, 0x0.0000000000000p+0),
532     HP(1e2, 0x0.0000000000000p+0),
533     HP(1e1, 0x0.0000000000000p+0),
534     HP(1e0, 0x0.0000000000000p+0),
535     HP(1e-1, -0x1.9999999999999p-58),
536     HP(1e-2, -0x1.eb851eb851eb8p-63),
537     HP(1e-3, -0x1.89374bc6a7ef9p-66),
538     HP(1e-4, -0x1.6a161e4f765fdp-68),
539     HP(1e-5, -0x1.ee78183f91e64p-71),
540     HP(1e-6, 0x1.b5a63f9a49c2cp-75),
541     HP(1e-7, 0x1.5e1e99483b023p-78),
542     HP(1e-8, -0x1.03023df2d4c94p-82),
543     HP(1e-9, -0x1.34674bfabb83bp-84),
544     HP(1e-10, -0x1.20a5465df8d2bp-88),
545     HP(1e-11, 0x1.7f7bc7b4d28a9p-91),
546     HP(1e-12, 0x1.97f27f0f6e885p-96),
547     HP(1e-13, -0x1.ecd79a5a0df94p-99),
548     HP(1e-14, 0x1.ea70909833de7p-107),
549     HP(1e-15, -0x1.937831647f5a0p-104),
550     HP(1e-16, 0x1.5b4c2ebe68798p-109),
551     HP(1e-17, -0x1.db7b2080a3029p-111),
552     HP(1e-18, -0x1.7c628066e8cedp-114),
553     HP(1e-19, 0x1.a52b31e9e3d06p-119),
554     HP(1e-20, 0x1.75447a5d8e535p-121),
555     HP(1e-21, 0x1.f769fb7e0b75ep-124),
556     HP(1e-22, -0x1.a7566d9cba769p-128),
557     HP(1e-23, 0x1.13badb829e078p-131),
558     HP(1e-24, 0x1.a96249354b393p-134),
559     HP(1e-25, -0x1.5762be11213e0p-138),
560     HP(1e-26, -0x1.12b564da80fe6p-141),
561     HP(1e-27, -0x1.b788a15d9b30ap-145),
562     HP(1e-28, 0x1.06c5e54eb70c4p-148),
563     HP(1e-29, 0x1.9f04b7722c09dp-151),
564     HP(1e-30, -0x1.e72f6d3e432b5p-154),
565     HP(1e-31, -0x1.85bf8a9835bc4p-157),
566     HP(1e-32, -0x1.a2cc10f3892d3p-161),
567     HP(1e-33, -0x1.4f09a7293a8a9p-164),
568     HP(1e-34, 0x1.5a5ead789df78p-167),
569     HP(1e-35, -0x1.e1aa86c4e6d2ep-174),
570     HP(1e-36, 0x1.696ef285e8eaep-174),
571     HP(1e-37, -0x1.4540d794df441p-177),
572     HP(1e-38, 0x1.2acb73de9ac64p-181),
573     HP(1e-39, 0x1.bbd5f64baf050p-184),
574     HP(1e-40, 0x1.631191d6259d9p-187),
575     HP(1e-41, -0x1.72524ee484eb4p-194),
576     HP(1e-42, -0x1.e3aa0fc74dc8ap-195),
577     HP(1e-43, -0x1.8e44064fb8b6ap-197),
578     HP(1e-44, 0x1.82c65c4d3edbbp-201),
579     HP(1e-45, 0x1.a27ac0f72f8bfp-206),
580     HP(1e-46, -0x1.e46a98d3d9f66p-209),
581     HP(1e-47, 0x1.afaab8f01e6e1p-212),
582     HP(1e-48, 0x1.595560c018580p-215),
583     HP(1e-49, 0x1.56eef38009bcdp-217),
584     HP(1e-50, -0x1.06d38332f4e12p-223),
585     HP(1e-51, -0x1.a4859eb7ee350p-227),
586     HP(1e-52, -0x1.506ae55ff1c40p-230),
587     HP(1e-53, -0x1.10156113305a6p-231),
588     HP(1e-54, -0x1.b355681eb3c3dp-235),
589     HP(1e-55, 0x1.eaaa326eb4b42p-241),
590     HP(1e-56, -0x1.6888948e87879p-241),
591     HP(1e-57, 0x1.45f922c12d2d2p-244),
592     HP(1e-58, -0x1.29a4953151516p-248),
593     HP(1e-59, -0x1.dc3a884ee8823p-252),
594     HP(1e-60, 0x1.b63792f412cb0p-255),
595     HP(1e-61, -0x1.d4a0573cbdc3fp-258),
596     HP(1e-62, -0x1.76e6ac3097cffp-261),
597     HP(1e-63, -0x1.f8b889c079732p-264),
598     HP(1e-64, 0x1.a53f2398d747bp-268),
599     HP(1e-65, 0x1.754c74a3894fep-270),
600     HP(1e-66, 0x1.775b0ed81dcc6p-275),
601     HP(1e-67, 0x1.62f139233f1e9p-277),
602     HP(1e-68, -0x1.4a7238b09a4dfp-280),
603     HP(1e-69, 0x1.227c7218a2b67p-284),
604     HP(1e-70, 0x1.b96c1ad4ef863p-291),
605     HP(1e-71, 0x1.afabce243f2d1p-290),
606     HP(1e-72, 0x1.1912e36d31e1cp-294),
607     HP(1e-73, 0x1.40f1c575b1b05p-301),
608     HP(1e-74, 0x1.b9b1c6f22b5e6p-301),
609     HP(1e-75, 0x1.615b058e89185p-304),
610     HP(1e-76, 0x1.e77c04720746ap-307),
611     HP(1e-77, 0x1.85fcd05b39055p-310),
612     HP(1e-78, 0x1.3290123e9aab2p-319),
613     HP(1e-79, 0x1.ea801d30f7783p-323),
614     HP(1e-80, 0x1.a5dccd879fc96p-321),
615     HP(1e-81, 0x1.517d71394ca11p-324),
616     HP(1e-82, 0x1.0dfdf42dd6e74p-327),
617     HP(1e-83, -0x1.8336795041c11p-331),
618     HP(1e-84, -0x1.35c52dd9ce341p-334),
619     HP(1e-85, 0x1.4391503d1c797p-338),
620     HP(1e-86, -0x1.e4f9131ac1690p-340),
621     HP(1e-87, -0x1.431d09ef37b67p-345),
622     HP(1e-88, 0x1.e52795a0501d6p-347),
623     HP(1e-89, -0x1.c48d76ff7fd0fp-351),
624     HP(1e-90, 0x1.7c76a00334606p-357),
625     HP(1e-91, -0x1.4d81dfff5becbp-358),
626     HP(1e-92, 0x1.1d96999aa01edp-362),
627     HP(1e-93, 0x1.d2b7b85220062p-363),
628     HP(1e-94, 0x1.5125f3b699a37p-367),
629     HP(1e-95, 0x1.03aca57b853e4p-372),
630     HP(1e-96, 0x1.cd88ede5810c7p-373),
631     HP(1e-97, -0x1.1d8b502a64b8dp-377),
632     HP(1e-98, 0x1.81f6f3114905bp-380),
633     HP(1e-99, -0x1.9350296249875p-385),
634     HP(1e-100, -0x1.42a68781d46c4p-388),
635     HP(1e-101, -0x1.4ddc3633ee91bp-390),
636     HP(1e-102, 0x1.5b4fd4a341250p-393),
637     HP(1e-103, 0x1.5ee6210535080p-397),
638     HP(1e-104, 0x1.e584e7375da00p-400),
639     HP(1e-105, 0x1.6f3b0b8bc9001p-404),
640     HP(1e-106, 0x1.f295a2d63a667p-407),
641     HP(1e-107, -0x1.576fb7608f5aap-415),
642     HP(1e-108, -0x1.aac595f8072aep-414),
643     HP(1e-109, 0x1.10baece64f769p-419),
644     HP(1e-110, -0x1.630dd09ebce84p-420),
645     HP(1e-111, -0x1.e8d7da1897203p-423),
646     HP(1e-112, 0x1.bea6a30bdaffap-427),
647     HP(1e-113, 0x1.310a9e795e65dp-431),
648     HP(1e-114, -0x1.1f955a35da3dap-433),
649     HP(1e-115, -0x1.cc2229efc395dp-437),
650     HP(1e-116, 0x1.4bf226ce4f740p-443),
651     HP(1e-117, -0x1.5735f83d234f3p-444),
652     HP(1e-118, 0x1.0e100c6afab47p-448),
653     HP(1e-119, -0x1.831985bb3bac0p-452),
654     HP(1e-120, 0x1.fd852e9d69dccp-455),
655     HP(1e-121, 0x1.979dbee454b0ap-458),
656     HP(1e-122, -0x1.c35a807177b95p-460),
657     HP(1e-123, -0x1.6915338df9611p-463),
658     HP(1e-124, 0x1.4588a38e6bb25p-466),
659     HP(1e-125, -0x1.762f1c7081f10p-472),
660     HP(1e-126, 0x1.4ec360b64c696p-473),
661     HP(1e-127, -0x1.1b94320f85bdcp-477),
662     HP(1e-128, -0x1.afa9c1a60497dp-480),
663     HP(1e-129, 0x1.d9de9847fc535p-483),
664     HP(1e-130, -0x1.b81ab96002f08p-486),
665     HP(1e-131, 0x1.cc21c3ffed2fdp-492),
666     HP(1e-132, 0x1.701b033324264p-495),
667     HP(1e-133, -0x1.4ffa98f5c591fp-496),
668     HP(1e-134, -0x1.4cc427efa2831p-500),
669     HP(1e-135, -0x1.0a3686594ecf4p-503),
670     HP(1e-136, -0x1.0573d5bb14ba8p-511),
671     HP(1e-137, 0x1.7f746aa07ded5p-511),
672     HP(1e-138, -0x1.cd04a22634077p-513),
673     HP(1e-139, -0x1.480769d6b9a58p-517),
674     HP(1e-140, 0x1.265a89dba3c3ep-521),
675     HP(1e-141, -0x1.23dbc8db58180p-523),
676     HP(1e-142, -0x1.d2f9415ef359ap-527),
677     HP(1e-143, 0x1.bd9efee73d51ep-530),
678     HP(1e-144, 0x1.647f32529774bp-533),
679     HP(1e-145, 0x1.e9ff5b7545f6fp-536),
680     HP(1e-146, -0x1.e0020e88b9b68p-541),
681     HP(1e-147, 0x1.b3318df905079p-544),
682     HP(1e-148, 0x1.7ae09f3068697p-546),
683     HP(1e-149, 0x1.8935309ae7b7cp-551),
684     HP(1e-150, -0x1.7c2297a9e74d6p-556),
685     HP(1e-151, 0x1.739624089c11dp-556),
686     HP(1e-152, -0x1.3d217cc5e98b5p-559),
687     HP(1e-153, -0x1.2e9bfad642788p-563),
688     HP(1e-154, 0x1.4f066ea92f3f3p-567),
689     HP(1e-155, -0x1.1b28e88ae79aep-571),
690     HP(1e-156, -0x1.3e105d045ca45p-573),
691     HP(1e-157, 0x1.67f2e8c94f7c8p-576),
692     HP(1e-158, -0x1.4670df5ef39c6p-579),
693     HP(1e-159, 0x1.7060d0d3827d8p-585),
694     HP(1e-160, 0x1.26b3da42cecadp-588),
695     HP(1e-161, -0x1.23b80f187a154p-590),
696     HP(1e-162, 0x1.7d065a52d1889p-593),
697     HP(1e-163, 0x1.fd9eaea8a7a07p-596),
698     HP(1e-164, 0x1.95cab10dd900bp-600),
699     HP(1e-165, -0x1.53ddc96d49973p-605),
700     HP(1e-166, -0x1.10c5f515db84ap-606),
701     HP(1e-167, -0x1.ad654efc5a107p-614),
702     HP(1e-168, -0x1.af11dd8c9e1a6p-613),
703     HP(1e-169, -0x1.181c95adc9c3ep-617),
704     HP(1e-170, 0x1.730576e9f0603p-621),
705     HP(1e-171, 0x1.28d12bee59e68p-624),
706     HP(1e-172, -0x1.22df88070f3d6p-626),
707     HP(1e-173, -0x1.d165a671b1fbcp-630),
708     HP(1e-174, 0x1.2a423d2859b47p-636),
709     HP(1e-175, 0x1.dd36c8408f872p-640),
710     HP(1e-176, 0x1.7dc56d0072d28p-643),
711     HP(1e-177, 0x1.bfc6f14cd8484p-643),
712     HP(1e-178, 0x1.6638c10a46a03p-646),
713     HP(1e-179, -0x1.ec172fdf1dff5p-651),
714     HP(1e-180, -0x1.89ac264c17ff7p-654),
715     HP(1e-181, -0x1.6a44dc1e6fffcp-656),
716     HP(1e-182, -0x1.21d0b01859996p-659),
717     HP(1e-183, -0x1.b0d59ad147abfp-666),
718     HP(1e-184, -0x1.c4e22914ed913p-666),
719     HP(1e-185, 0x1.7a5892ad42c52p-672),
720     HP(1e-186, 0x1.bf6f41de2046ep-672),
721     HP(1e-187, -0x1.9d37f40bfe3a2p-678),
722     HP(1e-188, 0x1.46f4cf30cd279p-679),
723     HP(1e-189, -0x1.60d5c0a5c246bp-682),
724     HP(1e-190, -0x1.35df3545a0e26p-687),
725     HP(1e-191, -0x1.efcb886f67d09p-691),
726     HP(1e-192, -0x1.fcc24e7cae5cep-692),
727     HP(1e-193, -0x1.946a172de3c7ep-696),
728     HP(1e-194, -0x1.daed16f93f4c6p-701),
729     HP(1e-195, -0x1.f895d1650ca8ep-702),
730     HP(1e-196, -0x1.8dbc823b47749p-706),
731     HP(1e-197, 0x1.6da4c5a8b4f14p-711),
732     HP(1e-198, 0x1.e2ba8dee8a96ap-712),
733     HP(1e-199, 0x1.3bee92fb55154p-717),
734     HP(1e-200, 0x1.f97db7f888220p-721),
735     HP(1e-201, 0x1.31e5f1981b3a0p-722),
736     HP(1e-202, -0x1.49c34a3fd46ffp-726),
737     HP(1e-203, -0x1.07cf6e9976bffp-729),
738     HP(1e-204, -0x1.8fe2eb7e2665bp-738),
739     HP(1e-205, -0x1.3fe8bc64eb849p-741),
740     HP(1e-206, -0x1.a9986fd1d8936p-740),
741     HP(1e-207, 0x1.bc296cdf42f83p-742),
742     HP(1e-208, -0x1.cfdedc1a30d30p-745),
743     HP(1e-209, -0x1.4c97c6904e1e6p-749),
744     HP(1e-210, -0x1.0a1305403e7ebp-752),
745     HP(1e-211, -0x1.a1a8d10031fefp-755),
746     HP(1e-212, 0x1.63beb199499b3p-759),
747     HP(1e-213, 0x1.1c988e143ae29p-762),
748     HP(1e-214, 0x1.b07a0b43624edp-765),
749     HP(1e-215, -0x1.4c0987942f81dp-769),
750     HP(1e-216, -0x1.09a139435934ap-772),
751     HP(1e-217, -0x1.a14dc769142a2p-775),
752     HP(1e-218, -0x1.02160bdb53769p-779),
753     HP(1e-219, -0x1.9cf012f8858a9p-783),
754     HP(1e-220, 0x1.3cffc34b2177bp-788),
755     HP(1e-221, -0x1.1acce51525d01p-790),
756     HP(1e-222, -0x1.3deb8ed542533p-792),
757     HP(1e-223, 0x1.36871b7795e13p-796),
758     HP(1e-224, -0x1.425b0740a9cadp-800),
759     HP(1e-225, 0x1.18a8637fbc154p-802),
760     HP(1e-226, 0x1.ad5382cc96776p-805),
761     HP(1e-227, 0x1.e21f37adbd8bdp-809),
762     HP(1e-228, -0x1.c967a6ea03ed0p-813),
763     HP(1e-229, -0x1.83c30f90ce5edp-815),
764     HP(1e-230, -0x1.9f9e7f4e16fe1p-819),
765     HP(1e-231, 0x1.346b356c83394p-824),
766     HP(1e-232, -0x1.1e3b843afeb5ep-826),
767     HP(1e-233, 0x1.8169fc9d9aa1ap-829),
768     HP(1e-234, 0x1.3454ca17aee7bp-832),
769     HP(1e-235, 0x1.ed54768c4b0c6p-836),
770     HP(1e-236, -0x1.a8893ac2f7294p-839),
771     HP(1e-237, 0x1.17e27729b5e24p-844),
772     HP(1e-238, 0x1.bfd0bea92303ap-848),
773     HP(1e-239, -0x1.6cd18688afb2dp-848),
774     HP(1e-240, 0x1.d6fb1e4a9a908p-853),
775     HP(1e-241, 0x1.78c8e5087ba6dp-856),
776     HP(1e-242, 0x1.2d6d8406c9524p-859),
777     HP(1e-243, 0x1.22bce691d541ap-865),
778     HP(1e-244, 0x1.b6ac7d74fbb9cp-865),
779     HP(1e-245, 0x1.5ef0645d962e3p-868),
780     HP(1e-246, 0x1.64b3d3c8f049fp-872),
781     HP(1e-247, -0x1.f0f3c0b032469p-877),
782     HP(1e-248, 0x1.a5a365d971612p-880),
783     HP(1e-249, -0x1.bdbea40f6c3f8p-882),
784     HP(1e-250, -0x1.6498833f89cc7p-885),
785     HP(1e-251, -0x1.41e80a64ec27cp-890),
786     HP(1e-252, 0x1.e5a32f0ad4bcep-892),
787     HP(1e-253, -0x1.aeb0a72a89027p-895),
788     HP(1e-254, 0x1.daa5e0aac5979p-898),
789     HP(1e-255, -0x1.de1b2aa952051p-905),
790     HP(1e-256, 0x1.39fa911155fefp-906),
791     HP(1e-257, 0x1.f65db4e88997fp-910),
792     HP(1e-258, 0x1.95bf1529d0a33p-912),
793     HP(1e-259, -0x1.ee9a557825e3dp-915),
794     HP(1e-260, 0x1.b56f773fc3603p-919),
795     HP(1e-261, 0x1.224bf1ff9f006p-923),
796     HP(1e-262, -0x1.62b9b0009b329p-927),
797     HP(1e-263, -0x1.1bc7c0007c287p-930),
798     HP(1e-264, -0x1.c60c66672d0d8p-934),
799     HP(1e-265, 0x1.c7f6147a425b9p-937),
800     HP(1e-266, 0x1.6cc4dd2e9b7c7p-940),
801     HP(1e-267, 0x1.23d0b0f215fd2p-943),
802     HP(1e-268, 0x1.4186ad2da2654p-945),
803     HP(1e-269, 0x1.01388a8ae8510p-948),
804     HP(1e-270, -0x1.97a588bb5917fp-952),
805     HP(1e-271, 0x1.20485f6a1f200p-955),
806     HP(1e-272, 0x1.b36d1921b2800p-958),
807     HP(1e-273, -0x1.d6dbebe50acccp-961),
808     HP(1e-274, 0x1.0ea0202b21eb8p-965),
809     HP(1e-275, 0x1.a54ce688e7efap-968),
810     HP(1e-276, -0x1.e228e12c13404p-971),
811     HP(1e-277, 0x1.f916c90c8f323p-976),
812     HP(1e-278, 0x1.96d5ea0506141p-978),
813     HP(1e-279, -0x1.20ee77fbfb231p-981),
814     HP(1e-280, 0x1.64e8d9a007c7cp-985),
815     HP(1e-281, -0x1.f04a14664d809p-990),
816     HP(1e-282, -0x1.8d081051d79a1p-993),
817     HP(1e-283, 0x1.c7965fdf435bfp-995),
818     HP(1e-284, -0x1.f3dc33679439ap-999),
819     HP(1e-285, -0x1.94be7af63b4a4p-1001),
820     HP(1e-286, -0x1.baca5e56c5439p-1005),
821     HP(1e-287, -0x1.2add63be086c3p-1009),
822     HP(1e-288, -0x1.44588e4c035e7p-1011),
823     HP(1e-289, -0x1.b569f519af297p-1017),
824     HP(1e-290, -0x1.f115310523084p-1018),
825     HP(1e-291, 0x1.b177b191618c5p-1022),
826 ];
827 
828 private char[] errol1(const double value,
829                       return ref char[512] digits,
830                       out int exponent) @nogc nothrow pure @safe
831 {
832     // Phase 1: Exponent Estimation
833     exponent = cast(int) (frexp(value) * 0.30103);
834     auto e = cast(size_t) (exponent + 307);
835 
836     if (e >= powersOf10.length)
837     {
838         exponent = powersOf10.length - 308;
839         e = powersOf10.length - 1;
840     }
841     HP t = powersOf10[e];
842 
843     HP scaledInput = t * value;
844 
845     while (scaledInput.base > 10.0
846         || (scaledInput.base == 10.0 && scaledInput.offset >= 0.0))
847     {
848         scaledInput.divideBy10();
849         ++exponent;
850         t.base /= 10.0;
851     }
852     while (scaledInput.base < 1.0
853         || (scaledInput.base == 1.0 && scaledInput.offset < 0.0))
854     {
855         scaledInput.multiplyBy10();
856         --exponent;
857         t.base *= 10.0;
858     }
859 
860     // Phase 2: Boundary Computation
861     const double factor = t.base / (2.0 + epsilon);
862 
863     // Upper narrow boundary
864     auto nMinus = HP(scaledInput.base, scaledInput.offset
865                                      + (previous(value) - value) * factor);
866     nMinus.normalize();
867 
868     // Lower narrow boundary
869     auto nPlus = HP(scaledInput.base, scaledInput.offset
870                                     + (next(value) - value) * factor);
871     nPlus.normalize();
872 
873     // Phase 3: Exponent Rectification
874     while (nPlus.base > 10.0 || (nPlus.base == 10.0 && nPlus.offset >= 0.0))
875     {
876         nMinus.divideBy10();
877         nPlus.divideBy10();
878         ++exponent;
879     }
880     while (nPlus.base < 1.0 || (nPlus.base == 1.0 && nPlus.offset < 0.0))
881     {
882         nMinus.multiplyBy10();
883         nPlus.multiplyBy10();
884         --exponent;
885     }
886 
887     // get_digits_hp
888     byte dMinus, dPlus;
889 
890     size_t i;
891     do
892     {
893         dMinus = cast(byte) nMinus.base;
894         dPlus = cast(byte) nPlus.base;
895 
896         if (nMinus.base == dMinus && nMinus.offset < 0.0)
897         {
898             --dMinus;
899         }
900         if (nPlus.base == dPlus && nPlus.offset < 0.0)
901         {
902             --dPlus;
903         }
904 
905         if (dMinus != dPlus)
906         {
907             digits[i] = cast(char) ('0' + cast(ubyte) ((dPlus + dMinus) / 2.0 + 0.5));
908             break;
909         }
910         else
911         {
912             digits[i] = cast(char) ('0' + cast(ubyte) dPlus);
913         }
914         ++i;
915 
916         nMinus.base -= dMinus;
917         nPlus.base -= dPlus;
918         nPlus.multiplyBy10();
919         nMinus.multiplyBy10();
920     }
921     while (nPlus.base != 0.0 || nPlus.offset != 0.0);
922 
923     return digits[0 .. i + 1];
924 }
925 
926 @nogc nothrow pure @safe unittest
927 {
928     char[512] buf;
929     int e;
930 
931     assert(errol1(18.51234334, buf, e) == "1851234334");
932     assert(e == 2);
933 
934     assert(errol1(0.23432e304, buf, e) == "23432");
935     assert(e == 304);
936 }
937 
938 private struct uint128
939 {
940     ulong[2] data;
941 
942     private struct DivMod
943     {
944         uint128 quotient;
945         uint128 remainder;
946     }
947 
948     this(ulong upper, ulong lower) @nogc nothrow pure @safe
949     {
950         this.data[0] = upper;
951         this.data[1] = lower;
952     }
953 
954     this(ulong lower) @nogc nothrow pure @safe
955     {
956         this.data[1] = lower;
957     }
958 
959     this(double value) @nogc nothrow pure @safe
960     {
961         FloatBits!double bits = { floating: value };
962         const ulong unbiased = bits.integral >> 52;
963 
964         this((bits.integral & 0xfffffffffffff) + 0x10000000000000);
965         this = this << (unbiased - 1075);
966     }
967 
968     ref uint128 opUnary(string op : "++")()
969     {
970         ++this.data[1];
971         if (this.data[1] == 0)
972         {
973             ++this.data[0];
974         }
975         return this;
976     }
977 
978     uint128 opBinary(string op : "+")(uint128 rhs) const
979     {
980         uint128 result;
981         result.data[1] = this.data[1] + rhs.data[1];
982         result.data[0] = this.data[0] + rhs.data[0];
983 
984         if (result.data[1] < this.data[1])
985         {
986             ++result.data[0];
987         }
988         return result;
989     }
990 
991     @nogc nothrow pure @safe unittest
992     {
993         assert((uint128() + uint128(1)) == uint128(1));
994         assert((uint128(ulong.max) + uint128(1)) == uint128(1, 0));
995     }
996 
997     uint128 opBinary(string op : "-")(uint128 rhs) const
998     {
999         uint128 result;
1000         result.data[1] = this.data[1] - rhs.data[1];
1001         result.data[0] = this.data[0] - rhs.data[0];
1002 
1003         if (result.data[1] > this.data[1])
1004         {
1005              --result.data[0];
1006         }
1007         return result;
1008     }
1009 
1010     ref uint128 opUnary(string op : "--")()
1011     {
1012         --this.data[1];
1013         if (this.data[1] == ulong.max)
1014         {
1015              --this.data[0];
1016         }
1017         return this;
1018     }
1019 
1020     @nogc nothrow pure @safe unittest
1021     {
1022         assert((uint128(1, 0) - uint128(1)) == uint128(ulong.max));
1023     }
1024 
1025     uint128 opBinary(string op : "&")(ulong rhs) const
1026     {
1027         return uint128(this.data[1] & rhs);
1028     }
1029 
1030     @nogc nothrow pure @safe unittest
1031     {
1032         assert((uint128(0xf0f0f, 0xf0f) & 0xf0f) == uint128(0xf0f));
1033     }
1034 
1035     uint128 opBinary(string op : ">>")(ulong shift) const
1036     {
1037         if (shift == 0)
1038         {
1039             return this;
1040         }
1041         else if (shift < 64)
1042         {
1043             const ulong lower = (this.data[0] << (64 - shift))
1044                               + (this.data[1] >> shift);
1045             return uint128(this.data[0] >> shift, lower);
1046         }
1047         else if (shift < 128)
1048         {
1049             return uint128((this.data[0] >> (shift - 64)));
1050         }
1051         return uint128();
1052     }
1053 
1054     @nogc nothrow pure @safe unittest
1055     {
1056         assert((uint128(ulong.max, ulong.max) >> 128) == uint128());
1057         assert((uint128(1, 2) >> 64) == uint128(1));
1058         assert((uint128(1, 2) >> 0) == uint128(1, 2));
1059         assert((uint128(1, 0) >> 1) == uint128(0x8000000000000000));
1060         assert((uint128(2, 0) >> 65) == uint128(1));
1061     }
1062 
1063     uint128 opBinary(string op : "<<")(ulong shift) const
1064     {
1065         if (shift == 0)
1066         {
1067             return this;
1068         }
1069         else if (shift < 64)
1070         {
1071             const ulong upper = (this.data[0] << shift)
1072                               + (this.data[1] >> (64 - shift));
1073             return uint128(upper, this.data[1] << shift);
1074         }
1075         else if (shift < 128)
1076         {
1077             return uint128(this.data[1] << (shift - 64), 0);
1078         }
1079         return uint128();
1080     }
1081 
1082     bool opEquals(uint128 that) const @nogc nothrow pure @safe
1083     {
1084         return equal(this.data[], that.data[]);
1085     }
1086 
1087     int opCmp(uint128 that) const @nogc nothrow pure @safe
1088     {
1089         if (this.data[0] > that.data[0]
1090          || (this.data[0] == that.data[0] && this.data[1] > that.data[1]))
1091         {
1092             return 1;
1093         }
1094         else if (this.data[0] == that.data[0] && this.data[1] == that.data[1])
1095         {
1096             return 0;
1097         }
1098         return -1;
1099     }
1100 
1101     bool opEquals(ulong that) const @nogc nothrow pure @safe
1102     {
1103         return this.data[0] == 0 && this.data[1] == that;
1104     }
1105 
1106     int opCmp(ulong that) const @nogc nothrow pure @safe
1107     {
1108         if (this.data[0] != 0 || (this.data[0] == 0 && this.data[1] > that))
1109         {
1110             return 1;
1111         }
1112         return (this.data[1] == that) ? 0 : -1;
1113     }
1114 
1115     @nogc nothrow pure @safe unittest
1116     {
1117         assert(uint128(1, 2) >= uint128(1, 2));
1118         assert(uint128(1, ulong.max) < uint128(2, 0));
1119         assert(uint128(40) < uint128(50));
1120     }
1121 
1122     @nogc nothrow pure @safe unittest
1123     {
1124         assert(uint128(1, 0) != uint128(1));
1125         assert(uint128(1, 2) == uint128(1, 2));
1126     }
1127 
1128     @nogc nothrow pure @safe unittest
1129     {
1130         assert(uint128(1, 2) <= uint128(1, 2));
1131     }
1132 
1133     @nogc nothrow pure @safe unittest
1134     {
1135         assert(uint128(1, 2) <= uint128(1, 2));
1136         assert(uint128(2, 0) > uint128(1, ulong.max));
1137         assert(uint128(50) > uint128(40));
1138     }
1139 
1140     @nogc nothrow pure @safe unittest
1141     {
1142         assert(uint128(1, 2) >= uint128(1, 2));
1143     }
1144 
1145     private @property ubyte bits() const @nogc nothrow pure @safe
1146     {
1147         ubyte count;
1148         if (this.data[0] > 0)
1149         {
1150             count = 64;
1151             for (ulong digit = this.data[0]; digit > 0; digit >>= 1)
1152             {
1153                 ++count;
1154             }
1155         }
1156         else
1157         {
1158             for (ulong digit = this.data[1]; digit > 0; digit >>= 1)
1159             {
1160                 ++count;
1161             }
1162         }
1163         return count;
1164     }
1165 
1166     @nogc nothrow pure @safe unittest
1167     {
1168         assert(uint128().bits == 0);
1169         assert(uint128(1, 0).bits == 65);
1170     }
1171 
1172     T opCast(T : bool)()
1173     {
1174         return this.data[0] != 0 || this.data[1] != 0;
1175     }
1176 
1177     T opCast(T : ulong)()
1178     {
1179         return this.data[1];
1180     }
1181 
1182     DivMod divMod(ulong rhs) const @nogc nothrow pure @safe
1183     in
1184     {
1185         assert(rhs != uint128(), "Division by 0");
1186     }
1187     do
1188     {
1189         if (rhs == 1)
1190         {
1191             return typeof(return)(this, uint128());
1192         }
1193         else if (this == rhs)
1194         {
1195             return typeof(return)(uint128(1), uint128());
1196         }
1197         else if (this == uint128() || this < rhs)
1198         {
1199             return typeof(return)(uint128(), this);
1200         }
1201 
1202         typeof(return) result;
1203         for (ubyte x = this.bits; x > 0; --x)
1204         {
1205             result.quotient  = result.quotient << 1;
1206             result.remainder = result.remainder << 1;
1207 
1208             if ((this >> (x - 1U)) & 1)
1209             {
1210                 ++result.remainder;
1211             }
1212 
1213             if (result.remainder >= rhs)
1214             {
1215                 if (result.remainder.data[1] < rhs)
1216                 {
1217                     --result.remainder.data[0];
1218                 }
1219                 result.remainder.data[1] -= rhs;
1220                 ++result.quotient;
1221             }
1222         }
1223         return result;
1224     }
1225 
1226     uint128 opBinary(string op : "/")(ulong rhs)
1227     {
1228         return divMod(rhs).quotient;
1229     }
1230 
1231     uint128 opBinary(string op : "%")(ulong rhs) const
1232     {
1233         return divMod(rhs).remainder;
1234     }
1235 }
1236 
1237 private double next(const double value) @nogc nothrow pure @safe
1238 {
1239     FloatBits!double bits = { floating: value };
1240     ++bits.integral;
1241     return bits.floating;
1242 }
1243 
1244 private double previous(const double value) @nogc nothrow pure @safe
1245 {
1246     FloatBits!double bits = { floating: value };
1247     --bits.integral;
1248     return bits.floating;
1249 }
1250 
1251 private uint128 raise2ToExp(double value) @nogc nothrow pure @safe
1252 {
1253     FloatBits!double bits = { floating: value };
1254 
1255     return uint128(1) << ((bits.integral >> 52) - 1023);
1256 }
1257 
1258 private int indexMismatch(ulong low, ulong high) @nogc nothrow pure @safe
1259 {
1260     enum ulong power10 = 10000000000UL;
1261     const ulong a = low / power10;
1262     const ulong b = high / power10;
1263     int index;
1264 
1265     if (a != b)
1266     {
1267         index = 10;
1268         low = a;
1269         high = b;
1270     }
1271 
1272     for (;; ++index)
1273     {
1274         low /= 10;
1275         high /= 10;
1276 
1277         if (low == high)
1278         {
1279             return index;
1280         }
1281     }
1282 }
1283 
1284 private char[] errol2(double value,
1285         return ref char[512] buffer,
1286         out int exponent) @nogc nothrow pure @safe
1287 in
1288 {
1289     assert(value > 9.007199254740992e15 && value < 3.40282366920938e38);
1290 }
1291 do
1292 {
1293     auto v = uint128(value);
1294     auto leftBoundary = v + raise2ToExp((value - previous(value)) / 2.0);
1295     auto rightBoundary = v - raise2ToExp((next(value) - value) / 2.0);
1296     FloatBits!double bits = { floating: value };
1297 
1298     if (bits.integral & 0x1)
1299     {
1300         --leftBoundary;
1301     }
1302     else
1303     {
1304         --rightBoundary;
1305     }
1306 
1307     enum ulong power19 = cast(ulong) 1e19;
1308 
1309     auto qr = leftBoundary.divMod(power19);
1310     auto low = cast(ulong) qr.remainder;
1311     const lowFactor = cast(ulong) (qr.quotient % power19);
1312 
1313     qr = rightBoundary.divMod(power19);
1314     auto high = cast(ulong) qr.remainder;
1315     const highFactor = cast(ulong) (qr.quotient % power19);
1316     size_t digitIndex;
1317 
1318     if (lowFactor != highFactor)
1319     {
1320         low = lowFactor;
1321         high = highFactor;
1322         v = v / cast(ulong) 1e18;
1323     }
1324     else
1325     {
1326         digitIndex = 1;
1327     }
1328 
1329     int mismatch = indexMismatch(low, high);
1330     ulong tens = 1;
1331     for (; digitIndex < mismatch; ++digitIndex)
1332     {
1333         tens *= 10;
1334     }
1335     const midpoint = cast(ulong) (v / tens);
1336 
1337     if (lowFactor != highFactor)
1338     {
1339         mismatch += 19;
1340     }
1341 
1342     char[21] intBuffer;
1343     auto intSlice = integral2String(midpoint, intBuffer);
1344 
1345     if (mismatch != 0)
1346     {
1347         if (intSlice[$ - 1] >= '5')
1348         {
1349             ++intSlice[$ - 2];
1350         }
1351         intSlice.popBack();
1352     }
1353     const begin = buffer.length - intSlice.length;
1354     tanya.memory.op.copy(intSlice, buffer[begin .. $]);
1355 
1356     exponent = cast(int) (intSlice.length + mismatch);
1357 
1358     return buffer[begin .. $];
1359 }
1360 
1361 @nogc nothrow pure @safe unittest
1362 {
1363     char[512] buf;
1364     int e;
1365 
1366     assert(errol2(9.007199254740994e15, buf, e) == "9007199254740994");
1367     assert(e == 16);
1368 
1369     assert(errol2(9.007199254740994e25, buf, e) == "9007199254740994");
1370     assert(e == 26);
1371 }
1372 
1373 private char[] errolFixed(double value,
1374         return ref char[512] buffer,
1375         out int exponent) @nogc nothrow pure @safe
1376 in
1377 {
1378     assert(value >= 16.0 && value <= 9.007199254740992e15);
1379 }
1380 do
1381 {
1382     auto decimal = cast(ulong) value;
1383     auto n = cast(double) decimal;
1384 
1385     double midpoint = value - n;
1386     double leftBoundary = (previous(value) - n + midpoint) / 2.0;
1387     double rightBoundary = (next(value) - n + midpoint) / 2.0;
1388 
1389     char[21] intBuffer;
1390     auto intSlice = integral2String(decimal, intBuffer);
1391     tanya.memory.op.copy(intSlice, buffer);
1392     exponent = cast(int) intSlice.length;
1393 
1394     size_t position = exponent;
1395     if (midpoint != 0.0)
1396     {
1397         while (midpoint != 0.0)
1398         {
1399             leftBoundary *= 10.0;
1400             const leftDigit = cast(ubyte) leftBoundary;
1401             leftBoundary -= leftDigit;
1402 
1403             midpoint *= 10.0;
1404             const middleDigit = cast(ubyte) midpoint;
1405             midpoint -= middleDigit;
1406 
1407             rightBoundary *= 10.0;
1408             const rightDigit = cast(ubyte) rightBoundary;
1409             rightBoundary -= rightDigit;
1410 
1411             buffer[position++] = cast(char) (middleDigit + '0');
1412 
1413             if (rightDigit != leftDigit || position > 50)
1414             {
1415                 break;
1416             }
1417         }
1418 
1419         if (midpoint > 0.5
1420          || ((midpoint == 0.5) && (buffer[position - 1] & 0x1)))
1421         {
1422             ++buffer[position - 1];
1423         }
1424     }
1425     else
1426     {
1427         for (; buffer[position - 1] == '0'; --position)
1428         {
1429             buffer[position - 1] = '\0';
1430         }
1431     }
1432 
1433     return buffer[0 .. position];
1434 }
1435 
1436 @nogc nothrow pure @safe unittest
1437 {
1438     char[512] num;
1439     int exponent;
1440     {
1441         assert(errolFixed(16.0, num, exponent) == "16");
1442         assert(exponent == 2);
1443     }
1444     {
1445         assert(errolFixed(38234.1234, num, exponent) == "382341234");
1446         assert(exponent == 5);
1447     }
1448 }
1449 
1450 private char[] errol3(double value,
1451                       return ref char[512] buffer,
1452                       out int exponent) @nogc nothrow pure @safe
1453 {
1454     static struct Pathology
1455     {
1456         ulong representation;
1457         string digits;
1458         int exponent;
1459     }
1460 
1461     static immutable Pathology[432] pathologies = [
1462         { 0x001d243f646eaf51, "40526371999771488", -307 },
1463         { 0x002d243f646eaf51, "81052743999542975", -307 },
1464         { 0x00ab7aa3d73f6658, "1956574196882425", -304 },
1465         { 0x00bb7aa3d73f6658, "391314839376485", -304 },
1466         { 0x00cb7aa3d73f6658, "78262967875297", -304 },
1467         { 0x00f5d15b26b80e30, "4971131903427841", -303 },
1468         { 0x010b7aa3d73f6658, "1252207486004752", -302 },
1469         { 0x011b7aa3d73f6658, "2504414972009504", -302 },
1470         { 0x012b7aa3d73f6658, "5008829944019008", -302 },
1471         { 0x0180a0f3c55062c5, "19398723835545928", -300 },
1472         { 0x0180a0f3c55062c6, "1939872383554593", -300 },
1473         { 0x0190a0f3c55062c5, "38797447671091856", -300 },
1474         { 0x0190a0f3c55062c6, "3879744767109186", -300 },
1475         { 0x01f393b456eef178, "29232758945460627", -298 },
1476         { 0x03719f08ccdccfe5, "44144884605471774", -291 },
1477         { 0x037be9d5a60850b5, "69928982131052126", -291 },
1478         { 0x03dc25ba6a45de02, "45129663866844427", -289 },
1479         { 0x05798e3445512a6e, "27497183057384368", -281 },
1480         { 0x05798e3445512a6f, "2749718305738437", -281 },
1481         { 0x05898e3445512a6e, "54994366114768736", -281 },
1482         { 0x05898e3445512a6f, "5499436611476874", -281 },
1483         { 0x06afdadafcacdf85, "17970091719480621", -275 },
1484         { 0x06bfdadafcacdf85, "35940183438961242", -275 },
1485         { 0x06ceb7f2c53db97f, "69316187906522606", -275 },
1486         { 0x06cfdadafcacdf85, "71880366877922484", -275 },
1487         { 0x06e8b03fd6894b66, "22283747288943228", -274 },
1488         { 0x06f8b03fd6894b66, "44567494577886457", -274 },
1489         { 0x07bfe89cf1bd76ac, "23593494977819109", -270 },
1490         { 0x07c1707c02068785, "25789638850173173", -270 },
1491         { 0x07cfe89cf1bd76ac, "47186989955638217", -270 },
1492         { 0x08567a3c8dc4bc9c, "17018905290641991", -267 },
1493         { 0x08667a3c8dc4bc9c, "34037810581283983", -267 },
1494         { 0x089c25584881552a, "3409719593752201", -266 },
1495         { 0x08ac25584881552a, "6819439187504402", -266 },
1496         { 0x08dfa7ebe304ee3d, "6135911659254281", -265 },
1497         { 0x08dfa7ebe304ee3e, "61359116592542813", -265 },
1498         { 0x096822507db6a8fd, "23951010625355228", -262 },
1499         { 0x097822507db6a8fd, "47902021250710456", -262 },
1500         { 0x09e41934d77659be, "51061856989121905", -260 },
1501         { 0x0b8f3d82e9356287, "53263359599109627", -252 },
1502         { 0x0c27b35936d56e27, "4137829457097561", -249 },
1503         { 0x0c27b35936d56e28, "41378294570975613", -249 },
1504         { 0x0c43165633977bc9, "13329597309520689", -248 },
1505         { 0x0c43165633977bca, "1332959730952069", -248 },
1506         { 0x0c53165633977bc9, "26659194619041378", -248 },
1507         { 0x0c53165633977bca, "2665919461904138", -248 },
1508         { 0x0c63165633977bc9, "53318389238082755", -248 },
1509         { 0x0c63165633977bca, "5331838923808276", -248 },
1510         { 0x0c7e9eddbbb259b4, "1710711888535566", -247 },
1511         { 0x0c8e9eddbbb259b4, "3421423777071132", -247 },
1512         { 0x0c9e9eddbbb259b4, "6842847554142264", -247 },
1513         { 0x0e104273b18918b0, "6096109271490509", -240 },
1514         { 0x0e104273b18918b1, "609610927149051", -240 },
1515         { 0x0e204273b18918b0, "12192218542981019", -239 },
1516         { 0x0e204273b18918b1, "1219221854298102", -239 },
1517         { 0x0e304273b18918b0, "24384437085962037", -239 },
1518         { 0x0e304273b18918b1, "2438443708596204", -239 },
1519         { 0x0f1d16d6d4b89689, "7147520638007367", -235 },
1520         { 0x0fd6ba8608faa6a8, "2287474118824999", -231 },
1521         { 0x0fd6ba8608faa6a9, "22874741188249992", -231 },
1522         { 0x0fe6ba8608faa6a8, "4574948237649998", -231 },
1523         { 0x0fe6ba8608faa6a9, "45749482376499984", -231 },
1524         { 0x1006b100e18e5c17, "18269851255456139", -230 },
1525         { 0x1016b100e18e5c17, "36539702510912277", -230 },
1526         { 0x104f48347c60a1be, "40298468695006992", -229 },
1527         { 0x105f48347c60a1be, "80596937390013985", -229 },
1528         { 0x10a4139a6b17b224, "16552474403007851", -227 },
1529         { 0x10b4139a6b17b224, "33104948806015703", -227 },
1530         { 0x12cb91d317c8ebe9, "39050270537318193", -217 },
1531         { 0x13627383c5456c5e, "26761990828289327", -214 },
1532         { 0x138fb24e492936f6, "1838927069906671", -213 },
1533         { 0x139fb24e492936f6, "3677854139813342", -213 },
1534         { 0x13afb24e492936f6, "7355708279626684", -213 },
1535         { 0x13f93bb1e72a2033, "18738512510673039", -211 },
1536         { 0x14093bb1e72a2033, "37477025021346077", -211 },
1537         { 0x1466cc4fc92a0fa6, "21670630627577332", -209 },
1538         { 0x1476cc4fc92a0fa6, "43341261255154663", -209 },
1539         { 0x148048cb468bc208, "619160875073638", -209 },
1540         { 0x149048cb468bc209, "12383217501472761", -208 },
1541         { 0x14a048cb468bc209, "24766435002945523", -208 },
1542         { 0x1504c0b3a63c1444, "2019986500244655", -206 },
1543         { 0x1514c0b3a63c1444, "403997300048931", -206 },
1544         { 0x161ba6008389068a, "35273912934356928", -201 },
1545         { 0x162ba6008389068a, "70547825868713855", -201 },
1546         { 0x168cfab1a09b49c4, "47323883490786093", -199 },
1547         { 0x175090684f5fe997, "22159015457577768", -195 },
1548         { 0x175090684f5fe998, "2215901545757777", -195 },
1549         { 0x176090684f5fe997, "44318030915155535", -195 },
1550         { 0x176090684f5fe998, "4431803091515554", -195 },
1551         { 0x17e4116d591ef1fb, "13745435592982211", -192 },
1552         { 0x17f4116d591ef1fb, "27490871185964422", -192 },
1553         { 0x1804116d591ef1fb, "54981742371928845", -192 },
1554         { 0x18a710b7a2ef18b7, "64710073234908765", -189 },
1555         { 0x18cde996371c6060, "33567940583589088", -188 },
1556         { 0x18d99fccca44882a, "57511323531737074", -188 },
1557         { 0x18dde996371c6060, "67135881167178176", -188 },
1558         { 0x199a2cf604c30d3f, "2406355597625261", -184 },
1559         { 0x19aa2cf604c30d3f, "4812711195250522", -184 },
1560         { 0x1b5ebddc6593c857, "75862936714499446", -176 },
1561         { 0x1c513770474911bd, "27843818440071113", -171 },
1562         { 0x1d1b1ad9101b1bfd, "1795518315109779", -167 },
1563         { 0x1d2b1ad9101b1bfd, "3591036630219558", -167 },
1564         { 0x1d3b1ad9101b1bfd, "7182073260439116", -167 },
1565         { 0x1e3035e7b5183922, "28150140033551147", -162 },
1566         { 0x1e4035e7b5183923, "563002800671023", -162 },
1567         { 0x1e5035e7b5183923, "1126005601342046", -161 },
1568         { 0x1e6035e7b5183923, "2252011202684092", -161 },
1569         { 0x1e7035e7b5183923, "4504022405368184", -161 },
1570         { 0x1fd5a79c4e71d028, "2523567903248961", -154 },
1571         { 0x1fe5a79c4e71d028, "5047135806497922", -154 },
1572         { 0x20cc29bc6879dfcd, "10754533488024391", -149 },
1573         { 0x20dc29bc6879dfcd, "21509066976048781", -149 },
1574         { 0x20e8823a57adbef8, "37436263604934127", -149 },
1575         { 0x20ec29bc6879dfcd, "43018133952097563", -149 },
1576         { 0x2104dab846e19e25, "1274175730310828", -148 },
1577         { 0x2114dab846e19e25, "2548351460621656", -148 },
1578         { 0x2124dab846e19e25, "5096702921243312", -148 },
1579         { 0x218ce77c2b3328fb, "45209911804158747", -146 },
1580         { 0x220ce77c2b3328fb, "11573737421864639", -143 },
1581         { 0x220ce77c2b3328fc, "1157373742186464", -143 },
1582         { 0x221ce77c2b3328fb, "23147474843729279", -143 },
1583         { 0x221ce77c2b3328fc, "2314747484372928", -143 },
1584         { 0x222ce77c2b3328fb, "46294949687458557", -143 },
1585         { 0x222ce77c2b3328fc, "4629494968745856", -143 },
1586         { 0x229197b290631476, "36067106647774144", -141 },
1587         { 0x233f346f9ed36b89, "65509428048152994", -138 },
1588         { 0x240a28877a09a4e0, "44986453555921307", -134 },
1589         { 0x240a28877a09a4e1, "4498645355592131", -134 },
1590         { 0x243441ed79830181, "27870735485790148", -133 },
1591         { 0x243441ed79830182, "2787073548579015", -133 },
1592         { 0x244441ed79830181, "55741470971580295", -133 },
1593         { 0x244441ed79830182, "557414709715803", -133 },
1594         { 0x245441ed79830181, "11148294194316059", -132 },
1595         { 0x245441ed79830182, "1114829419431606", -132 },
1596         { 0x246441ed79830181, "22296588388632118", -132 },
1597         { 0x246441ed79830182, "2229658838863212", -132 },
1598         { 0x247441ed79830181, "44593176777264236", -132 },
1599         { 0x247441ed79830182, "4459317677726424", -132 },
1600         { 0x248b23b50fc204db, "11948502190822011", -131 },
1601         { 0x249b23b50fc204db, "23897004381644022", -131 },
1602         { 0x24ab23b50fc204db, "47794008763288043", -131 },
1603         { 0x2541e4ee41180c0a, "32269008655522087", -128 },
1604         { 0x2633dc6227de9148, "1173600085235347", -123 },
1605         { 0x2643dc6227de9148, "2347200170470694", -123 },
1606         { 0x2653dc6227de9148, "4694400340941388", -123 },
1607         { 0x277aacfcb88c92d6, "16528675364037979", -117 },
1608         { 0x277aacfcb88c92d7, "1652867536403798", -117 },
1609         { 0x278aacfcb88c92d6, "33057350728075958", -117 },
1610         { 0x278aacfcb88c92d7, "3305735072807596", -117 },
1611         { 0x279aacfcb88c92d6, "66114701456151916", -117 },
1612         { 0x279aacfcb88c92d7, "6611470145615192", -117 },
1613         { 0x279b5cd8bbdd8770, "67817280930489786", -117 },
1614         { 0x27bbb4c6bd8601bd, "27467428267063488", -116 },
1615         { 0x27cbb4c6bd8601bd, "54934856534126976", -116 },
1616         { 0x289d52af46e5fa69, "4762882274418243", -112 },
1617         { 0x289d52af46e5fa6a, "47628822744182433", -112 },
1618         { 0x28b04a616046e074, "10584182832040541", -111 },
1619         { 0x28c04a616046e074, "21168365664081082", -111 },
1620         { 0x28d04a616046e074, "42336731328162165", -111 },
1621         { 0x297c2c31a31998ae, "74973710847373845", -108 },
1622         { 0x2a3eeff57768f88c, "33722866731879692", -104 },
1623         { 0x2a4eeff57768f88c, "67445733463759384", -104 },
1624         { 0x2b8e3a0aeed7be19, "69097540994131414", -98 },
1625         { 0x2bdec922478c0421, "22520091703825729", -96 },
1626         { 0x2beec922478c0421, "45040183407651457", -96 },
1627         { 0x2c2379f099a86227, "45590931008842566", -95 },
1628         { 0x2cc7c3fba45c1271, "5696647848853893", -92 },
1629         { 0x2cc7c3fba45c1272, "56966478488538934", -92 },
1630         { 0x2cf4f14348a4c5db, "40159515855058247", -91 },
1631         { 0x2d04f14348a4c5db, "8031903171011649", -91 },
1632         { 0x2d44f14348a4c5db, "12851045073618639", -89 },
1633         { 0x2d44f14348a4c5dc, "1285104507361864", -89 },
1634         { 0x2d54f14348a4c5db, "25702090147237278", -89 },
1635         { 0x2d54f14348a4c5dc, "2570209014723728", -89 },
1636         { 0x2d5a8c931c19b77a, "3258302752792233", -89 },
1637         { 0x2d64f14348a4c5db, "51404180294474556", -89 },
1638         { 0x2d64f14348a4c5dc, "5140418029447456", -89 },
1639         { 0x2d6a8c931c19b77a, "6516605505584466", -89 },
1640         { 0x2efc1249e96b6d8d, "23119896893873391", -81 },
1641         { 0x2f0c1249e96b6d8d, "46239793787746783", -81 },
1642         { 0x2f0f6b23cfe98807, "51753157237874753", -81 },
1643         { 0x2fa387cf9cb4ad4e, "32943123175907307", -78 },
1644         { 0x2fe91b9de4d5cf31, "67761208324172855", -77 },
1645         { 0x3081eab25ad0fcf7, "49514357246452655", -74 },
1646         { 0x308ddc7e975c5045, "8252392874408775", -74 },
1647         { 0x308ddc7e975c5046, "82523928744087755", -74 },
1648         { 0x309ddc7e975c5045, "1650478574881755", -73 },
1649         { 0x30addc7e975c5045, "330095714976351", -73 },
1650         { 0x30bddc7e975c5045, "660191429952702", -73 },
1651         { 0x3149190e30e46c1d, "28409785190323268", -70 },
1652         { 0x3150ed9bd6bfd003, "3832399419240467", -70 },
1653         { 0x3159190e30e46c1d, "56819570380646536", -70 },
1654         { 0x317d2ec75df6ba2a, "26426943389906988", -69 },
1655         { 0x318d2ec75df6ba2a, "52853886779813977", -69 },
1656         { 0x321aedaa0fc32ac8, "2497072464210591", -66 },
1657         { 0x322aedaa0fc32ac8, "4994144928421182", -66 },
1658         { 0x32448050091c3c24, "15208651188557789", -65 },
1659         { 0x32548050091c3c24, "30417302377115577", -65 },
1660         { 0x328f5a18504dfaac, "37213051060716888", -64 },
1661         { 0x329f5a18504dfaac, "74426102121433776", -64 },
1662         { 0x3336dca59d035820, "55574205388093594", -61 },
1663         { 0x33beef5e1f90ac34, "1925091640472375", -58 },
1664         { 0x33ceef5e1f90ac34, "385018328094475", -58 },
1665         { 0x33deef5e1f90ac34, "77003665618895", -58 },
1666         { 0x33eeef5e1f90ac35, "15400733123779001", -57 },
1667         { 0x33feef5e1f90ac35, "30801466247558002", -57 },
1668         { 0x340eef5e1f90ac35, "61602932495116004", -57 },
1669         { 0x341eef5e1f90ac35, "12320586499023201", -56 },
1670         { 0x34228f9edfbd3420, "14784703798827841", -56 },
1671         { 0x342eef5e1f90ac35, "24641172998046401", -56 },
1672         { 0x34328f9edfbd3420, "29569407597655683", -56 },
1673         { 0x343eef5e1f90ac35, "49282345996092803", -56 },
1674         { 0x344eef5e1f90ac35, "9856469199218561", -56 },
1675         { 0x345eef5e1f90ac35, "19712938398437121", -55 },
1676         { 0x346eef5e1f90ac35, "39425876796874242", -55 },
1677         { 0x347eef5e1f90ac35, "78851753593748485", -55 },
1678         { 0x35008621c4199208, "21564764513659432", -52 },
1679         { 0x35108621c4199208, "43129529027318865", -52 },
1680         { 0x35e0ac2e7f90b8a3, "35649516398744314", -48 },
1681         { 0x35ef1de1f7f14439, "66534156679273626", -48 },
1682         { 0x361dde4a4ab13e09, "51091836539008967", -47 },
1683         { 0x366b870de5d93270, "15068094409836911", -45 },
1684         { 0x367b870de5d93270, "30136188819673822", -45 },
1685         { 0x368b870de5d93270, "60272377639347644", -45 },
1686         { 0x375b20c2f4f8d49f, "4865841847892019", -41 },
1687         { 0x375b20c2f4f8d4a0, "48658418478920193", -41 },
1688         { 0x37f25d342b1e33e5, "33729482964455627", -38 },
1689         { 0x3854faba79ea92ec, "24661175471861008", -36 },
1690         { 0x3854faba79ea92ed, "2466117547186101", -36 },
1691         { 0x3864faba79ea92ec, "49322350943722016", -36 },
1692         { 0x3864faba79ea92ed, "4932235094372202", -36 },
1693         { 0x3a978cfcab31064c, "19024128529074359", -25 },
1694         { 0x3a978cfcab31064d, "1902412852907436", -25 },
1695         { 0x3aa78cfcab31064c, "38048257058148717", -25 },
1696         { 0x3aa78cfcab31064d, "3804825705814872", -25 },
1697         { 0x47f52d02c7e14af7, "45035996273704964", 39 },
1698         { 0x490cd230a7ff47c3, "80341375308088225", 44 },
1699         { 0x4919d9577de925d5, "14411294198511291", 45 },
1700         { 0x4929d9577de925d5, "28822588397022582", 45 },
1701         { 0x4931159a8bd8a240, "38099461575161174", 45 },
1702         { 0x4939d9577de925d5, "57645176794045164", 45 },
1703         { 0x49ccadd6dd730c96, "32745697577386472", 48 },
1704         { 0x49dcadd6dd730c96, "65491395154772944", 48 },
1705         { 0x4a6bb6979ae39c49, "32402369146794532", 51 },
1706         { 0x4a7bb6979ae39c49, "64804738293589064", 51 },
1707         { 0x4b9a32ac316fb3ab, "16059290466419889", 57 },
1708         { 0x4b9a32ac316fb3ac, "1605929046641989", 57 },
1709         { 0x4baa32ac316fb3ab, "32118580932839778", 57 },
1710         { 0x4baa32ac316fb3ac, "3211858093283978", 57 },
1711         { 0x4bba32ac316fb3ab, "64237161865679556", 57 },
1712         { 0x4bba32ac316fb3ac, "6423716186567956", 57 },
1713         { 0x4c85564fb098c955, "42859354584576066", 61 },
1714         { 0x4cef20b1a0d7f626, "4001624164855121", 63 },
1715         { 0x4cff20b1a0d7f626, "8003248329710242", 63 },
1716         { 0x4e2e2785c3a2a20a, "4064803033949531", 69 },
1717         { 0x4e2e2785c3a2a20b, "40648030339495312", 69 },
1718         { 0x4e3e2785c3a2a20a, "8129606067899062", 69 },
1719         { 0x4e3e2785c3a2a20b, "81296060678990625", 69 },
1720         { 0x4e6454b1aef62c8d, "4384946084578497", 70 },
1721         { 0x4e80fde34c996086, "1465909318208761", 71 },
1722         { 0x4e90fde34c996086, "2931818636417522", 71 },
1723         { 0x4ea9a2c2a34ac2f9, "8846583389443709", 71 },
1724         { 0x4ea9a2c2a34ac2fa, "884658338944371", 71 },
1725         { 0x4eb9a2c2a34ac2f9, "17693166778887419", 72 },
1726         { 0x4eb9a2c2a34ac2fa, "1769316677888742", 72 },
1727         { 0x4ec9a2c2a34ac2f9, "35386333557774838", 72 },
1728         { 0x4ec9a2c2a34ac2fa, "3538633355777484", 72 },
1729         { 0x4ed9a2c2a34ac2f9, "70772667115549675", 72 },
1730         { 0x4ed9a2c2a34ac2fa, "7077266711554968", 72 },
1731         { 0x4f28750ea732fdae, "21606114462319112", 74 },
1732         { 0x4f38750ea732fdae, "43212228924638223", 74 },
1733         { 0x503ca9bade45b94a, "3318949537676913", 79 },
1734         { 0x504ca9bade45b94a, "6637899075353826", 79 },
1735         { 0x513843e10734fa57, "18413733104063271", 84 },
1736         { 0x514843e10734fa57, "36827466208126543", 84 },
1737         { 0x51a3274280201a89, "18604316837693468", 86 },
1738         { 0x51b3274280201a89, "37208633675386937", 86 },
1739         { 0x51e71760b3c0bc13, "35887030159858487", 87 },
1740         { 0x521f6a5025e71a61, "39058878597126768", 88 },
1741         { 0x522f6a5025e71a61, "78117757194253536", 88 },
1742         { 0x52c6a47d4e7ec633, "57654578150150385", 91 },
1743         { 0x55693ba3249a8511, "2825769263311679", 104 },
1744         { 0x55793ba3249a8511, "5651538526623358", 104 },
1745         { 0x574fe0403124a00e, "38329392744333992", 113 },
1746         { 0x575fe0403124a00e, "76658785488667984", 113 },
1747         { 0x57763ae2caed4528, "2138446062528161", 114 },
1748         { 0x57863ae2caed4528, "4276892125056322", 114 },
1749         { 0x57d561def4a9ee32, "1316415380484425", 116 },
1750         { 0x57e561def4a9ee32, "263283076096885", 116 },
1751         { 0x57f561def4a9ee32, "52656615219377", 116 },
1752         { 0x580561def4a9ee31, "10531323043875399", 117 },
1753         { 0x581561def4a9ee31, "21062646087750798", 117 },
1754         { 0x582561def4a9ee31, "42125292175501597", 117 },
1755         { 0x584561def4a9ee31, "16850116870200639", 118 },
1756         { 0x585561def4a9ee31, "33700233740401277", 118 },
1757         { 0x5935ede8cce30845, "56627018760181905", 122 },
1758         { 0x59d0dd8f2788d699, "44596066840334405", 125 },
1759         { 0x5b45ed1f039cebfe, "48635409059147446", 132 },
1760         { 0x5b55ed1f039cebfe, "9727081811829489", 132 },
1761         { 0x5b55ed1f039cebff, "972708181182949", 132 },
1762         { 0x5beaf5b5378aa2e5, "61235700073843246", 135 },
1763         { 0x5bfaf5b5378aa2e5, "12247140014768649", 136 },
1764         { 0x5c0af5b5378aa2e5, "24494280029537298", 136 },
1765         { 0x5c1af5b5378aa2e5, "48988560059074597", 136 },
1766         { 0x5c4ef3052ef0a361, "4499029632233837", 137 },
1767         { 0x5c6cf45d333da323, "16836228873919609", 138 },
1768         { 0x5e1780695036a679, "18341526859645389", 146 },
1769         { 0x5e2780695036a679, "36683053719290777", 146 },
1770         { 0x5e54ec8fd70420c7, "2612787385440923", 147 },
1771         { 0x5e64ec8fd70420c7, "5225574770881846", 147 },
1772         { 0x5e6b5e2f86026f05, "6834859331393543", 147 },
1773         { 0x5f9aeac2d1ea2695, "35243988108650928", 153 },
1774         { 0x5faaeac2d1ea2695, "70487976217301855", 153 },
1775         { 0x6009813653f62db7, "42745323906998127", 155 },
1776         { 0x611260322d04d50b, "40366692112133834", 160 },
1777         { 0x624be064a3fb2725, "32106017483029628", 166 },
1778         { 0x625be064a3fb2725, "64212034966059256", 166 },
1779         { 0x64112a13daa46fe4, "10613173493886741", 175 },
1780         { 0x64212a13daa46fe4, "21226346987773482", 175 },
1781         { 0x64312a13daa46fe4, "42452693975546964", 175 },
1782         { 0x671dcfee6690ffc6, "51886190678901447", 189 },
1783         { 0x672dcfee6690ffc6, "10377238135780289", 190 },
1784         { 0x673dcfee6690ffc6, "20754476271560579", 190 },
1785         { 0x674dcfee6690ffc6, "41508952543121158", 190 },
1786         { 0x675dcfee6690ffc6, "83017905086242315", 190 },
1787         { 0x677a77581053543b, "29480080280199528", 191 },
1788         { 0x678a77581053543b, "58960160560399056", 191 },
1789         { 0x6820ee7811241ad3, "38624526316654214", 194 },
1790         { 0x682d3683fa3d1ee0, "66641177824100826", 194 },
1791         { 0x699873e3758bc6b3, "4679330956996797", 201 },
1792         { 0x699cb490951e8515, "5493127645170153", 201 },
1793         { 0x6a6cc08102f0da5b, "45072812455233127", 205 },
1794         { 0x6b3ef9beaa7aa583, "39779219869333628", 209 },
1795         { 0x6b3ef9beaa7aa584, "3977921986933363", 209 },
1796         { 0x6b4ef9beaa7aa583, "79558439738667255", 209 },
1797         { 0x6b4ef9beaa7aa584, "7955843973866726", 209 },
1798         { 0x6b7896beb0c66eb9, "50523702331566894", 210 },
1799         { 0x6b7b86d8c3df7cd1, "56560320317673966", 210 },
1800         { 0x6bdf20938e7414bb, "40933393326155808", 212 },
1801         { 0x6be6c9e14b7c22c4, "59935550661561155", 212 },
1802         { 0x6bef20938e7414bb, "81866786652311615", 212 },
1803         { 0x6bf6c9e14b7c22c3, "1198711013231223", 213 },
1804         { 0x6bf6c9e14b7c22c4, "11987110132312231", 213 },
1805         { 0x6c06c9e14b7c22c3, "2397422026462446", 213 },
1806         { 0x6c06c9e14b7c22c4, "23974220264624462", 213 },
1807         { 0x6c16c9e14b7c22c3, "4794844052924892", 213 },
1808         { 0x6c16c9e14b7c22c4, "47948440529248924", 213 },
1809         { 0x6ce75d226331d03a, "40270821632825953", 217 },
1810         { 0x6cf75d226331d03a, "8054164326565191", 217 },
1811         { 0x6d075d226331d03a, "16108328653130381", 218 },
1812         { 0x6d175d226331d03a, "32216657306260762", 218 },
1813         { 0x6d275d226331d03a, "64433314612521525", 218 },
1814         { 0x6d4b9445072f4374, "30423431424080128", 219 },
1815         { 0x6d5a3bdac4f00f33, "57878622568856074", 219 },
1816         { 0x6d5b9445072f4374, "60846862848160256", 219 },
1817         { 0x6e4a2fbffdb7580c, "18931483477278361", 224 },
1818         { 0x6e5a2fbffdb7580c, "37862966954556723", 224 },
1819         { 0x6e927edd0dbb8c08, "4278822588984689", 225 },
1820         { 0x6e927edd0dbb8c09, "42788225889846894", 225 },
1821         { 0x6ee1c382c3819a0a, "1315044757954692", 227 },
1822         { 0x6ef1c382c3819a0a, "2630089515909384", 227 },
1823         { 0x70f60cf8f38b0465, "14022275014833741", 237 },
1824         { 0x71060cf8f38b0465, "28044550029667482", 237 },
1825         { 0x7114390c68b888ce, "5143975308105889", 237 },
1826         { 0x71160cf8f38b0465, "56089100059334965", 237 },
1827         { 0x714fb4840532a9e5, "64517311884236306", 238 },
1828         { 0x71b1d7cb7eae05d9, "46475406389115295", 240 },
1829         { 0x727fca36c06cf106, "3391607972972965", 244 },
1830         { 0x728fca36c06cf106, "678321594594593", 244 },
1831         { 0x72eba10d818fdafd, "3773057430100257", 246 },
1832         { 0x72fba10d818fdafd, "7546114860200514", 246 },
1833         { 0x737a37935f3b71c9, "1833078106007497", 249 },
1834         { 0x738a37935f3b71c9, "3666156212014994", 249 },
1835         { 0x73972852443155ae, "64766168833734675", 249 },
1836         { 0x739a37935f3b71c9, "7332312424029988", 249 },
1837         { 0x754fe46e378bf132, "1197160149212491", 258 },
1838         { 0x754fe46e378bf133, "11971601492124911", 258 },
1839         { 0x755fe46e378bf132, "2394320298424982", 258 },
1840         { 0x755fe46e378bf133, "23943202984249821", 258 },
1841         { 0x756fe46e378bf132, "4788640596849964", 258 },
1842         { 0x756fe46e378bf133, "47886405968499643", 258 },
1843         { 0x76603d7cb98edc58, "1598075144577112", 263 },
1844         { 0x76603d7cb98edc59, "15980751445771122", 263 },
1845         { 0x76703d7cb98edc58, "3196150289154224", 263 },
1846         { 0x76703d7cb98edc59, "31961502891542243", 263 },
1847         { 0x782f7c6a9ad432a1, "83169412421960475", 271 },
1848         { 0x78447e17e7814ce7, "21652206566352648", 272 },
1849         { 0x78547e17e7814ce7, "43304413132705296", 272 },
1850         { 0x7856d2aa2fc5f2b5, "48228872759189434", 272 },
1851         { 0x7964066d88c7cab8, "5546524276967009", 277 },
1852         { 0x799d696737fe68c7, "65171333649148234", 278 },
1853         { 0x7ace779fddf21621, "3539481653469909", 284 },
1854         { 0x7ace779fddf21622, "35394816534699092", 284 },
1855         { 0x7ade779fddf21621, "7078963306939818", 284 },
1856         { 0x7ade779fddf21622, "70789633069398184", 284 },
1857         { 0x7bc3b063946e10ae, "14990287287869931", 289 },
1858         { 0x7bd3b063946e10ae, "29980574575739863", 289 },
1859         { 0x7c0c283ffc61c87d, "34300126555012788", 290 },
1860         { 0x7c1c283ffc61c87d, "68600253110025576", 290 },
1861         { 0x7c31926c7a7122ba, "17124434349589332", 291 },
1862         { 0x7c41926c7a7122ba, "34248868699178663", 291 },
1863         { 0x7d0a85c6f7fba05d, "2117392354885733", 295 },
1864         { 0x7d1a85c6f7fba05d, "4234784709771466", 295 },
1865         { 0x7d52a5daf9226f04, "47639264836707725", 296 },
1866         { 0x7d8220e1772428d7, "37049827284413546", 297 },
1867         { 0x7d9220e1772428d7, "7409965456882709", 297 },
1868         { 0x7da220e1772428d7, "14819930913765419", 298 },
1869         { 0x7db220e1772428d7, "29639861827530837", 298 },
1870         { 0x7df22815078cb97b, "47497368114750945", 299 },
1871         { 0x7dfe5aceedf1c1f1, "79407577493590275", 299 },
1872         { 0x7e022815078cb97b, "9499473622950189", 299 },
1873         { 0x7e122815078cb97b, "18998947245900378", 300 },
1874         { 0x7e222815078cb97b, "37997894491800756", 300 },
1875         { 0x7e8a9b45a91f1700, "35636409637317792", 302 },
1876         { 0x7e9a9b45a91f1700, "71272819274635585", 302 },
1877         { 0x7eb6202598194bee, "23707742595255608", 303 },
1878         { 0x7ec490abad057752, "4407140524515149", 303 },
1879         { 0x7ec6202598194bee, "47415485190511216", 303 },
1880         { 0x7ee3c8eeb77b8d05, "16959746108988652", 304 },
1881         { 0x7ef3c8eeb77b8d05, "33919492217977303", 304 },
1882         { 0x7ef5bc471d5456c7, "37263572163337027", 304 },
1883         { 0x7f03c8eeb77b8d05, "6783898443595461", 304 },
1884         { 0x7f13c8eeb77b8d05, "13567796887190921", 305 },
1885         { 0x7f23c8eeb77b8d05, "27135593774381842", 305 },
1886         { 0x7f33c8eeb77b8d05, "54271187548763685", 305 },
1887         { 0x7f5594223f5654bf, "2367662756557091", 306 },
1888         { 0x7f6594223f5654bf, "4735325513114182", 306 },
1889         { 0x7f9914e03c9260ee, "44032152438472327", 307 },
1890         { 0x7fb82baa4ae611dc, "16973149506391291", 308 },
1891         { 0x7fc82baa4ae611dc, "33946299012782582", 308 },
1892         { 0x7fd82baa4ae611dc, "67892598025565165", 308 },
1893         { 0x7fefffffffffffff, "17976931348623157", 309 },
1894     ];
1895 
1896     short low;
1897     short high = pathologies.length - 1;
1898     const FloatBits!double bits = { value };
1899 
1900     while (high >= low)
1901     {
1902         const short middle = (low + high) / 2;
1903         if (pathologies[middle].representation == bits.integral)
1904         {
1905             exponent = pathologies[middle].exponent;
1906             tanya.memory.op.copy(pathologies[middle].digits, buffer);
1907             return buffer[0 .. pathologies[middle].digits.length];
1908         }
1909         else if (pathologies[middle].representation < bits.integral)
1910         {
1911             low = cast(short) (middle + 1);
1912         }
1913         else
1914         {
1915             high = cast(short) (middle - 1);
1916         }
1917     }
1918     return null;
1919 }
1920 
1921 @nogc nothrow pure @safe unittest
1922 {
1923     int exponent;
1924     char[512] buffer;
1925 
1926     assert(errol3(double.max, buffer, exponent) == "17976931348623157");
1927     assert(exponent == 309);
1928 
1929     assert(errol3(0.67892598025565165e308, buffer, exponent) == "67892598025565165");
1930     assert(exponent == 308);
1931 
1932     assert(errol3(0.40526371999771488e-307, buffer, exponent) == "40526371999771488");
1933     assert(exponent == -307);
1934 
1935     assert(errol3(0.81052743999542975e-307, buffer, exponent) == "81052743999542975");
1936     assert(exponent == -307);
1937 
1938     assert(errol3(0.810307, buffer, exponent) is null);
1939 }
1940 
1941 /*
1942  * Given a float value, returns the significant bits, and the position of the
1943  * decimal point in $(D_PARAM exponent). +/-Inf and NaN are specified by
1944  * special values returned in the $(D_PARAM exponent). Sing bit is set in
1945  * $(D_PARAM sign).
1946  */
1947 private const(char)[] real2String(double value,
1948                                   return ref char[512] buffer,
1949                                   out int exponent,
1950                                   out bool sign) @nogc nothrow pure @trusted
1951 {
1952     const FloatBits!double bits = { value };
1953 
1954     exponent = (bits.integral >> 52) & 0x7ff;
1955     sign = signBit(value);
1956     if (sign)
1957     {
1958         value = -value;
1959     }
1960 
1961     if (exponent == 0x7ff) // Is NaN or Inf?
1962     {
1963         exponent = special;
1964         return (bits.integral & ((1UL << 52) - 1)) != 0 ? "NaN" : "Inf";
1965     }
1966     else if (exponent == 0 && (bits.integral << 1) == 0) // Is zero?
1967     {
1968         exponent = 1;
1969         buffer[0] = '0';
1970         return buffer[0 .. 1];
1971     }
1972 
1973     auto digits = errol3(value, buffer, exponent);
1974     if (digits !is null)
1975     {
1976         return buffer;
1977     }
1978     else if (value >= 16.0 && value <= 9.007199254740992e15)
1979     {
1980         return errolFixed(value, buffer, exponent);
1981     }
1982     else if (value > 9.007199254740992e15 && value < 3.40282366920938e38)
1983     {
1984         return errol2(value, buffer, exponent);
1985     }
1986     else
1987     {
1988         return errol1(value, buffer, exponent);
1989     }
1990 }
1991 
1992 private void formatReal(T, OR)(ref T arg, OR result)
1993 if (isFloatingPoint!T)
1994 {
1995     char[512] buffer; // Big enough for e+308 or e-307.
1996     char[8] tail = 0;
1997     char[] bufferSlice = buffer[64 .. $];
1998     uint precision = 6;
1999     bool negative;
2000     int decimalPoint;
2001 
2002     // Read the double into a string.
2003     auto realString = real2String(arg, buffer, decimalPoint, negative);
2004     auto length = cast(uint) realString.length;
2005 
2006     // Clamp the precision and delete extra zeros after clamp.
2007     uint n = precision;
2008     if (length > precision)
2009     {
2010         length = precision;
2011     }
2012     while ((length > 1) && (precision != 0) && (realString[length - 1] == '0'))
2013     {
2014         --precision;
2015         --length;
2016     }
2017 
2018     if (negative)
2019     {
2020         put(result, "-");
2021     }
2022     if (decimalPoint == special)
2023     {
2024         put(result, realString);
2025         return;
2026     }
2027 
2028     // Should we use sceintific notation?
2029     if ((decimalPoint <= -4) || (decimalPoint > cast(int) n))
2030     {
2031         if (precision > length)
2032         {
2033             precision = length - 1;
2034         }
2035         else if (precision > 0)
2036         {
2037            // When using scientific notation, there is one digit before the
2038            // decimal.
2039            --precision;
2040         }
2041 
2042         // Handle leading chars.
2043         bufferSlice.front = realString[0];
2044         bufferSlice.popFront();
2045 
2046         if (precision != 0)
2047         {
2048             bufferSlice.front = period;
2049             bufferSlice.popFront();
2050         }
2051 
2052         // Handle after decimal.
2053         if ((length - 1) > precision)
2054         {
2055             length = precision + 1;
2056         }
2057         tanya.memory.op.copy(realString[1 .. length], bufferSlice);
2058         bufferSlice.popFrontExactly(length - 1);
2059 
2060         // Dump the exponent.
2061         tail[1] = 'e';
2062         --decimalPoint;
2063         if (decimalPoint < 0)
2064         {
2065             tail[2] = '-';
2066             decimalPoint = -decimalPoint;
2067         }
2068         else
2069         {
2070             tail[2] = '+';
2071         }
2072 
2073         n = decimalPoint >= 100 ? 5 : 4;
2074 
2075         tail[0] = cast(char) n;
2076         while (true)
2077         {
2078             tail[n] = '0' + decimalPoint % 10;
2079             if (n <= 3)
2080             {
2081                 break;
2082             }
2083             --n;
2084             decimalPoint /= 10;
2085         }
2086     }
2087     else
2088     {
2089         if (decimalPoint > 0)
2090         {
2091             precision = decimalPoint < (cast(int) length)
2092                       ? length - decimalPoint
2093                       : 0;
2094         }
2095         else
2096         {
2097             precision = -decimalPoint
2098                       + (precision > length ? length : precision);
2099         }
2100 
2101         // Handle the three decimal varieties.
2102         if (decimalPoint <= 0)
2103         {
2104             // Handle 0.000*000xxxx.
2105             bufferSlice.front = '0';
2106             bufferSlice.popFront();
2107 
2108             if (precision != 0)
2109             {
2110                 bufferSlice.front = period;
2111                 bufferSlice.popFront();
2112             }
2113             n = -decimalPoint;
2114             if (n > precision)
2115             {
2116                 n = precision;
2117             }
2118 
2119             tanya.memory.op.fill!'0'(bufferSlice[0 .. n]);
2120             bufferSlice.popFrontExactly(n);
2121 
2122             if ((length + n) > precision)
2123             {
2124                 length = precision - n;
2125             }
2126 
2127             tanya.memory.op.copy(realString[0 .. length], bufferSlice);
2128             bufferSlice.popFrontExactly(length);
2129         }
2130         else if (cast(uint) decimalPoint >= length)
2131         {
2132             // Handle xxxx000*000.0.
2133             n = 0;
2134             do
2135             {
2136                 bufferSlice.front = realString[n];
2137                 bufferSlice.popFront();
2138                 ++n;
2139             }
2140             while (n < length);
2141             if (n < cast(uint) decimalPoint)
2142             {
2143                 n = decimalPoint - n;
2144 
2145                 tanya.memory.op.fill!'0'(bufferSlice[0 .. n]);
2146                 bufferSlice.popFrontExactly(n);
2147             }
2148             if (precision != 0)
2149             {
2150                 bufferSlice.front = period;
2151                 bufferSlice.popFront();
2152             }
2153         }
2154         else
2155         {
2156             // Handle xxxxx.xxxx000*000.
2157             n = 0;
2158             do
2159             {
2160                 bufferSlice.front = realString[n];
2161                 bufferSlice.popFront();
2162                 ++n;
2163             }
2164             while (n < cast(uint) decimalPoint);
2165 
2166             if (precision > 0)
2167             {
2168                 bufferSlice.front = period;
2169                 bufferSlice.popFront();
2170             }
2171             if ((length - decimalPoint) > precision)
2172             {
2173                 length = precision + decimalPoint;
2174             }
2175 
2176             tanya.memory.op.copy(realString[n .. length], bufferSlice);
2177             bufferSlice.popFrontExactly(length - n);
2178         }
2179     }
2180 
2181     // Get the length that we've copied.
2182     length = cast(uint) (buffer.length - bufferSlice.length);
2183 
2184     put(result, buffer[64 .. length]); // Number.
2185     put(result, tail[1 .. tail[0] + 1]); // Tail.
2186 }
2187 
2188 private void formatStruct(T, OR)(ref T arg, OR result)
2189 if (is(T == struct))
2190 {
2191     template pred(alias f)
2192     {
2193         static if (f == "this")
2194         {
2195             // Exclude context pointer from nested structs.
2196             enum bool pred = false;
2197         }
2198         else
2199         {
2200             enum bool pred = !isSomeFunction!(__traits(getMember, arg, f));
2201         }
2202     }
2203     alias fields = Filter!(pred, __traits(allMembers, T));
2204 
2205     put(result, T.stringof);
2206     put(result, "(");
2207     static if (fields.length > 0)
2208     {
2209         printToString!"{}"(result, __traits(getMember, arg, fields[0]));
2210         foreach (field; fields[1 .. $])
2211         {
2212             put(result, ", ");
2213             printToString!"{}"(result, __traits(getMember, arg, field));
2214         }
2215     }
2216     put(result, ")");
2217 }
2218 
2219 private void formatRange(T, OR)(ref T arg, OR result)
2220 if (isInputRange!T && !isInfinite!T)
2221 {
2222     put(result, "[");
2223     if (!arg.empty)
2224     {
2225         printToString!"{}"(result, arg.front);
2226         arg.popFront();
2227     }
2228     foreach (e; arg)
2229     {
2230         put(result, ", ");
2231         printToString!"{}"(result, e);
2232     }
2233     put(result, "]");
2234 }
2235 
2236 private void printToString(string fmt, OR, Args...)(ref OR result,
2237                                                     auto ref Args args)
2238 {
2239     alias Arg = Args[0];
2240 
2241     static if (is(Unqual!Arg == typeof(null))) // null
2242     {
2243         put(result, "null");
2244     }
2245     else static if (is(Unqual!Arg == bool)) // Boolean
2246     {
2247         put(result, args[0] ? "true" : "false");
2248     }
2249     else static if (is(Arg == enum)) // Enum
2250     {
2251         foreach (m; __traits(allMembers, Arg))
2252         {
2253             if (args[0] == __traits(getMember, Arg, m))
2254             {
2255                 put(result, m);
2256             }
2257         }
2258     }
2259     else static if (isSomeChar!Arg || isSomeString!Arg) // String or char
2260     {
2261         put(result, args[0]);
2262     }
2263     else static if (isInputRange!Arg
2264                  && !isInfinite!Arg
2265                  && isSomeChar!(ElementType!Arg)) // Stringish range
2266     {
2267         put(result, args[0]);
2268     }
2269     else static if (isInputRange!Arg && !isInfinite!Arg)
2270     {
2271         formatRange(args[0], result);
2272     }
2273     else static if (is(typeof(args[0].toString(result)) == OR))
2274     {
2275         static if (is(Arg == class) || is(Arg == interface))
2276         {
2277             if (args[0] is null)
2278             {
2279                 put(result, "null");
2280             }
2281             else
2282             {
2283                 result = args[0].toString(result);
2284             }
2285         }
2286         else
2287         {
2288             result = args[0].toString(result);
2289         }
2290     }
2291     else static if (is(Arg == class))
2292     {
2293         put(result, args[0] is null ? "null" : args[0].toString());
2294     }
2295     else static if (is(Arg == interface))
2296     {
2297         put(result, Arg.classinfo.name);
2298     }
2299     else static if (is(Arg == struct))
2300     {
2301         formatStruct(args[0], result);
2302     }
2303     else static if (is(Arg == union))
2304     {
2305         put(result, Arg.stringof);
2306     }
2307     else static if (isFloatingPoint!Arg) // Float
2308     {
2309         formatReal(args[0], result);
2310     }
2311     else static if (isPointer!Arg) // Pointer
2312     {
2313         char[size_t.sizeof * 2] buffer;
2314         size_t position = buffer.length;
2315         auto address = cast(size_t) args[0];
2316 
2317         do // Write at least "0" if the pointer is null.
2318         {
2319             buffer[--position] = lowerHexDigits[cast(size_t) (address & 15)];
2320             address >>= 4;
2321         }
2322         while (address != 0);
2323 
2324         put(result, "0x");
2325         put(result, buffer[position .. $]);
2326     }
2327     else static if (isIntegral!Arg) // Integer
2328     {
2329         char[21] buffer;
2330         put(result, integral2String(args[0], buffer));
2331     }
2332     else
2333     {
2334         static assert(false,
2335                       "Formatting type " ~ Arg.stringof ~ " is not supported");
2336     }
2337 }
2338 
2339 /**
2340  * Produces a string according to the specified format.
2341  *
2342  * Params:
2343  *  fmt  = Format.
2344  *  Args = Types of the arguments.
2345  *  args = Arguments.
2346  *
2347  * Returns: Formatted string.
2348  */
2349 String format(string fmt, Args...)(auto ref Args args)
2350 {
2351     String formatted;
2352     sformat!fmt(backInserter(formatted), args);
2353     return formatted;
2354 }
2355 
2356 /**
2357  * Produces a string according to the specified format and writes it into an
2358  * output range. $(D_PSYMBOL sformat) writes the final string in chunks, so the
2359  * output range should be in output range for `const(char)[]`.
2360  *
2361  * Params:
2362  *  fmt    = Format.
2363  *  R      = Output range type.
2364  *  output = Output range.
2365  *  args   = Arguments.
2366  *
2367  * Returns: $(D_PARAM output).
2368  */
2369 R sformat(string fmt, R, Args...)(R output, auto ref Args args)
2370 if (isOutputRange!(R, const(char)[]))
2371 {
2372     alias Specs = ParseFmt!fmt;
2373     enum bool FormatSpecFilter(alias spec) = is(typeof(spec) == FormatSpec);
2374     static assert((Filter!(FormatSpecFilter, ParseFmt!fmt)).length == Args.length,
2375                   "Number of the arguments doesn't match the format string");
2376 
2377     foreach (spec; Specs)
2378     {
2379         static if (FormatSpecFilter!spec)
2380         {
2381             printToString!"{}"(output, args[spec.position]);
2382         }
2383         else static if (isSomeString!(typeof(spec)))
2384         {
2385             put(output, spec);
2386         }
2387         else
2388         {
2389             static assert(false, "Format string parsed incorrectly");
2390         }
2391     }
2392     return output;
2393 }
2394 
2395 private struct FormatSpec
2396 {
2397     const size_t position;
2398 }
2399 
2400 // Returns the position of `tag` in `fmt`. If `tag` can't be found, returns the
2401 // length of  `fmt`.
2402 private size_t specPosition(string fmt, char tag)()
2403 {
2404     foreach (i, c; fmt)
2405     {
2406         if (c == tag)
2407         {
2408             return i;
2409         }
2410     }
2411     return fmt.length;
2412 }
2413 
2414 private template ParseFmt(string fmt, size_t arg = 0, size_t pos = 0)
2415 {
2416     static if (fmt.length == 0)
2417     {
2418         alias ParseFmt = AliasSeq!();
2419     }
2420     else static if (fmt[0] == '{')
2421     {
2422         static if (fmt.length > 1 && fmt[1] == '{')
2423         {
2424             enum size_t pos = specPosition!(fmt[2 .. $], '{') + 2;
2425             alias ParseFmt = AliasSeq!(fmt[1 .. pos],
2426                                        ParseFmt!(fmt[pos .. $], arg, pos));
2427         }
2428         else
2429         {
2430             enum size_t pos = specPosition!(fmt[1 .. $], '}') + 1;
2431             static if (pos >= fmt.length)
2432             {
2433                 static assert(false, "Enclosing '}' is missing");
2434             }
2435             else static if (pos == 1)
2436             {
2437                 alias ParseFmt = AliasSeq!(FormatSpec(arg),
2438                                            ParseFmt!(fmt[2 .. $], arg + 1, 2));
2439             }
2440             else
2441             {
2442                 static assert(false, "Argument formatting isn't supported");
2443             }
2444         }
2445     }
2446     else
2447     {
2448         enum size_t pos = specPosition!(fmt, '{');
2449         alias ParseFmt = AliasSeq!(fmt[0 .. pos],
2450                                    ParseFmt!(fmt[pos .. $], arg, pos));
2451     }
2452 }
2453 
2454 @nogc nothrow pure @safe unittest
2455 {
2456     static assert(ParseFmt!"".length == 0);
2457 
2458     static assert(ParseFmt!"asdf".length == 1);
2459     static assert(ParseFmt!"asdf"[0] == "asdf");
2460 
2461     static assert(ParseFmt!"{}".length == 1);
2462 
2463     static assert(ParseFmt!"aasdf{}qwer"[2] == "qwer");
2464     static assert(ParseFmt!"{}{}".length == 2);
2465 }