@@ -34,6 +34,184 @@ struct Decimal(uint size64)
34
34
// /
35
35
BigInt! size64 coefficient;
36
36
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
+
37
215
@safe :
38
216
39
217
// /
@@ -214,184 +392,6 @@ struct Decimal(uint size64)
214
392
return buffer.data.idup;
215
393
}
216
394
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
-
395
395
/+ +
396
396
Mir parsing supports up-to quadruple precision. The conversion error is 0 ULP for normal numbers.
397
397
Subnormal numbers with an exponent greater than or equal to -512 have upper error bound equal to 1 ULP. +/
0 commit comments