@@ -34,6 +34,184 @@ struct Decimal(uint size64)
3434 // /
3535 BigInt! size64 coefficient;
3636
37+ // /
38+ void toString (C = char , W)(scope ref W w, NumericSpec spec = NumericSpec.init) const
39+ if (isSomeChar! C && isMutable! C)
40+ {
41+ assert (spec.format == NumericSpec.Format.exponent || spec.format == NumericSpec.Format.human);
42+ import mir.utility: _expect;
43+ // handle special values
44+ if (_expect(exponent == exponent.max, false ))
45+ {
46+ static immutable C[3 ] nan = " nan" ;
47+ static immutable C[4 ] ninf = " -inf" ;
48+ static immutable C[4 ] pinf = " +inf" ;
49+ w.put(coefficient.length == 0 ? coefficient.sign ? ninf[] : pinf[] : nan[]);
50+ return ;
51+ }
52+
53+ C[coefficientBufferLength + 16 ] buffer0 = void ;
54+ auto buffer = buffer0[0 .. $ - 16 ];
55+
56+ size_t coefficientLength;
57+ static if (size_t .sizeof == 8 )
58+ {
59+ if (__ctfe)
60+ {
61+ uint [coefficient.data.length * 2 ] data;
62+ foreach (i; 0 .. coefficient.length)
63+ {
64+ auto l = cast (uint )coefficient.data[i];
65+ auto h = cast (uint )(coefficient.data[i] >> 32 );
66+ data[i * 2 + 0 ] = l;
67+ data[i * 2 + 1 ] = h;
68+ }
69+ auto work = BigUIntView! uint (data);
70+ work = work.topLeastSignificantPart(coefficient.length * 2 ).normalized;
71+ coefficientLength = work.toStringImpl(buffer);
72+ }
73+ else
74+ {
75+ BigInt! size64 work = coefficient;
76+ coefficientLength = work.view.unsigned.toStringImpl(buffer);
77+ }
78+ }
79+ else
80+ {
81+ BigInt! size64 work = coefficient;
82+ coefficientLength = work.view.unsigned.toStringImpl(buffer);
83+ }
84+
85+ C[1 ] sign = coefficient.sign ? " -" : " +" ;
86+ bool addSign = coefficient.sign || spec.plus;
87+ long s = this .exponent + coefficientLength;
88+
89+ alias zeros = zerosImpl! C;
90+
91+ if (spec.format == NumericSpec.Format.human)
92+ {
93+ if (! spec.separatorCount)
94+ spec.separatorCount = 3 ;
95+ void putL (scope const (C)[] b)
96+ {
97+ assert (b.length);
98+
99+ if (addSign)
100+ w.put(sign[]);
101+
102+ auto r = b.length % spec.separatorCount;
103+ if (r == 0 )
104+ r = spec.separatorCount;
105+ C[1 ] sep = spec.separatorChar;
106+ goto LS ;
107+ do
108+ {
109+ w.put(sep[]);
110+ LS :
111+ w.put(b[0 .. r]);
112+ b = b[r .. $];
113+ r = spec.separatorCount;
114+ }
115+ while (b.length);
116+ }
117+
118+ // try print decimal form without exponent
119+ // up to 6 digits exluding leading 0. or final .0
120+ if (s <= 0 )
121+ {
122+ // 0.001....
123+ // 0.0001
124+ // 0.00001
125+ // 0.000001
126+ // If separatorChar is defined lets be less greed for space.
127+ if (this .exponent >= - 6 || s >= - 2 - (spec.separatorChar != 0 ) * 3 )
128+ {
129+ if (addSign)
130+ w.put(sign[]);
131+ w.put(zeros[0 .. cast (sizediff_t )(- s + 2 )]);
132+ w.put(buffer[$ - coefficientLength .. $]);
133+ return ;
134+ }
135+ }
136+ else
137+ if (this .exponent >= 0 )
138+ {
139+ // /dddddd.0
140+ if (! spec.separatorChar)
141+ {
142+ if (s <= 6 )
143+ {
144+ buffer[$ - coefficientLength - 1 ] = sign[0 ];
145+ w.put(buffer[$ - coefficientLength - addSign .. $]);
146+ w.put(zeros[($ - (cast (sizediff_t )this .exponent + 2 )) .. $]);
147+ return ;
148+ }
149+ }
150+ else
151+ {
152+ if (s <= 12 )
153+ {
154+ buffer0[$ - 16 .. $] = ' 0' ;
155+ putL(buffer0[$ - coefficientLength - 16 .. $ - 16 + cast (sizediff_t )this .exponent]);
156+ w.put(zeros[$ - 2 .. $]);
157+ return ;
158+ }
159+ }
160+ }
161+ else
162+ {
163+ // /dddddd.0
164+ if (! spec.separatorChar)
165+ {
166+ // /dddddd.d....
167+ if (s <= 6 || coefficientLength <= 6 )
168+ {
169+ buffer[$ - coefficientLength - 1 ] = sign[0 ];
170+ w.put(buffer[$ - coefficientLength - addSign .. $ - coefficientLength + cast (sizediff_t )s]);
171+ T2 :
172+ buffer[$ - coefficientLength + cast (sizediff_t )s - 1 ] = ' .' ;
173+ w.put(buffer[$ - coefficientLength + cast (sizediff_t )s - 1 .. $]);
174+ return ;
175+ }
176+ }
177+ else
178+ {
179+ if (s <= 12 || coefficientLength <= 12 )
180+ {
181+ putL(buffer[$ - coefficientLength .. $ - coefficientLength + cast (sizediff_t )s]);
182+ goto T2 ;
183+ }
184+ }
185+ }
186+ }
187+
188+ assert (coefficientLength);
189+
190+ long exponent = s - 1 ;
191+
192+ if (coefficientLength > 1 )
193+ {
194+ auto c = buffer[$ - coefficientLength];
195+ buffer[$ - coefficientLength] = ' .' ;
196+ buffer[$ - ++ coefficientLength] = c;
197+ }
198+
199+ buffer[$ - coefficientLength - 1 ] = sign[0 ];
200+ w.put(buffer[$ - coefficientLength - addSign .. $]);
201+
202+ import mir.format_impl: printSignedToTail;
203+
204+ static if (exponent.sizeof == 8 )
205+ enum N = 21 ;
206+ else
207+ enum N = 11 ;
208+
209+ // prints e+/-exponent
210+ auto expLength = printSignedToTail(exponent, buffer0[$ - N - 16 .. $ - 16 ], ' +' );
211+ buffer[$ - ++ expLength] = spec.exponentChar;
212+ w.put(buffer[$ - expLength .. $]);
213+ }
214+
37215@safe :
38216
39217 // /
@@ -214,184 +392,6 @@ struct Decimal(uint size64)
214392 return buffer.data.idup;
215393 }
216394
217- // /
218- void toString (C = char , W)(scope ref W w, NumericSpec spec = NumericSpec.init) const
219- if (isSomeChar! C && isMutable! C)
220- {
221- assert (spec.format == NumericSpec.Format.exponent || spec.format == NumericSpec.Format.human);
222- import mir.utility: _expect;
223- // handle special values
224- if (_expect(exponent == exponent.max, false ))
225- {
226- static immutable C[3 ] nan = " nan" ;
227- static immutable C[4 ] ninf = " -inf" ;
228- static immutable C[4 ] pinf = " +inf" ;
229- w.put(coefficient.length == 0 ? coefficient.sign ? ninf[] : pinf[] : nan[]);
230- return ;
231- }
232-
233- C[coefficientBufferLength + 16 ] buffer0 = void ;
234- auto buffer = buffer0[0 .. $ - 16 ];
235-
236- size_t coefficientLength;
237- static if (size_t .sizeof == 8 )
238- {
239- if (__ctfe)
240- {
241- uint [coefficient.data.length * 2 ] data;
242- foreach (i; 0 .. coefficient.length)
243- {
244- auto l = cast (uint )coefficient.data[i];
245- auto h = cast (uint )(coefficient.data[i] >> 32 );
246- data[i * 2 + 0 ] = l;
247- data[i * 2 + 1 ] = h;
248- }
249- auto work = BigUIntView! uint (data);
250- work = work.topLeastSignificantPart(coefficient.length * 2 ).normalized;
251- coefficientLength = work.toStringImpl(buffer);
252- }
253- else
254- {
255- BigInt! size64 work = coefficient;
256- coefficientLength = work.view.unsigned.toStringImpl(buffer);
257- }
258- }
259- else
260- {
261- BigInt! size64 work = coefficient;
262- coefficientLength = work.view.unsigned.toStringImpl(buffer);
263- }
264-
265- C[1 ] sign = coefficient.sign ? " -" : " +" ;
266- bool addSign = coefficient.sign || spec.plus;
267- long s = this .exponent + coefficientLength;
268-
269- alias zeros = zerosImpl! C;
270-
271- if (spec.format == NumericSpec.Format.human)
272- {
273- if (! spec.separatorCount)
274- spec.separatorCount = 3 ;
275- void putL (scope const (C)[] b)
276- {
277- assert (b.length);
278-
279- if (addSign)
280- w.put(sign[]);
281-
282- auto r = b.length % spec.separatorCount;
283- if (r == 0 )
284- r = spec.separatorCount;
285- C[1 ] sep = spec.separatorChar;
286- goto LS ;
287- do
288- {
289- w.put(sep[]);
290- LS :
291- w.put(b[0 .. r]);
292- b = b[r .. $];
293- r = spec.separatorCount;
294- }
295- while (b.length);
296- }
297-
298- // try print decimal form without exponent
299- // up to 6 digits exluding leading 0. or final .0
300- if (s <= 0 )
301- {
302- // 0.001....
303- // 0.0001
304- // 0.00001
305- // 0.000001
306- // If separatorChar is defined lets be less greed for space.
307- if (this .exponent >= - 6 || s >= - 2 - (spec.separatorChar != 0 ) * 3 )
308- {
309- if (addSign)
310- w.put(sign[]);
311- w.put(zeros[0 .. cast (sizediff_t )(- s + 2 )]);
312- w.put(buffer[$ - coefficientLength .. $]);
313- return ;
314- }
315- }
316- else
317- if (this .exponent >= 0 )
318- {
319- // /dddddd.0
320- if (! spec.separatorChar)
321- {
322- if (s <= 6 )
323- {
324- buffer[$ - coefficientLength - 1 ] = sign[0 ];
325- w.put(buffer[$ - coefficientLength - addSign .. $]);
326- w.put(zeros[($ - (cast (sizediff_t )this .exponent + 2 )) .. $]);
327- return ;
328- }
329- }
330- else
331- {
332- if (s <= 12 )
333- {
334- buffer0[$ - 16 .. $] = ' 0' ;
335- putL(buffer0[$ - coefficientLength - 16 .. $ - 16 + cast (sizediff_t )this .exponent]);
336- w.put(zeros[$ - 2 .. $]);
337- return ;
338- }
339- }
340- }
341- else
342- {
343- // /dddddd.0
344- if (! spec.separatorChar)
345- {
346- // /dddddd.d....
347- if (s <= 6 || coefficientLength <= 6 )
348- {
349- buffer[$ - coefficientLength - 1 ] = sign[0 ];
350- w.put(buffer[$ - coefficientLength - addSign .. $ - coefficientLength + cast (sizediff_t )s]);
351- T2 :
352- buffer[$ - coefficientLength + cast (sizediff_t )s - 1 ] = ' .' ;
353- w.put(buffer[$ - coefficientLength + cast (sizediff_t )s - 1 .. $]);
354- return ;
355- }
356- }
357- else
358- {
359- if (s <= 12 || coefficientLength <= 12 )
360- {
361- putL(buffer[$ - coefficientLength .. $ - coefficientLength + cast (sizediff_t )s]);
362- goto T2 ;
363- }
364- }
365- }
366- }
367-
368- assert (coefficientLength);
369-
370- long exponent = s - 1 ;
371-
372- if (coefficientLength > 1 )
373- {
374- auto c = buffer[$ - coefficientLength];
375- buffer[$ - coefficientLength] = ' .' ;
376- buffer[$ - ++ coefficientLength] = c;
377- }
378-
379- buffer[$ - coefficientLength - 1 ] = sign[0 ];
380- w.put(buffer[$ - coefficientLength - addSign .. $]);
381-
382- import mir.format_impl: printSignedToTail;
383-
384- static if (exponent.sizeof == 8 )
385- enum N = 21 ;
386- else
387- enum N = 11 ;
388-
389- // prints e+/-exponent
390- auto expLength = printSignedToTail(exponent, buffer0[$ - N - 16 .. $ - 16 ], ' +' );
391- buffer[$ - ++ expLength] = spec.exponentChar;
392- w.put(buffer[$ - expLength .. $]);
393- }
394-
395395 /+ +
396396 Mir parsing supports up-to quadruple precision. The conversion error is 0 ULP for normal numbers.
397397 Subnormal numbers with an exponent greater than or equal to -512 have upper error bound equal to 1 ULP. +/
0 commit comments