Skip to content

Commit 1050b3c

Browse files
committed
fixup decimal toString
1 parent 9d4a259 commit 1050b3c

File tree

1 file changed

+178
-178
lines changed

1 file changed

+178
-178
lines changed

source/mir/bignum/decimal.d

Lines changed: 178 additions & 178 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)