summaryrefslogtreecommitdiff
path: root/src/pkg/strconv/decimal.go
blob: 898a77dc77a6744410b53c1a36835e08c0644876 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Multiprecision decimal numbers.
// For floating-point formatting only; not general purpose.
// Only operations are assign and (binary) left/right shift.
// Can do binary floating point in multiprecision decimal precisely
// because 2 divides 10; cannot do decimal floating point
// in multiprecision binary precisely.

package strconv

import "bytes"

type decimal struct {
	// TODO(rsc): Can make d[] a bit smaller and add
	// truncated bool;
	d	[2000]byte;	// digits
	nd	int;		// number of digits used
	dp	int;		// decimal point
}

func (a *decimal) String() string {
	n := 10 + a.nd;
	if a.dp > 0 {
		n += a.dp
	}
	if a.dp < 0 {
		n += -a.dp
	}

	buf := make([]byte, n);
	w := 0;
	switch {
	case a.nd == 0:
		return "0"

	case a.dp <= 0:
		// zeros fill space between decimal point and digits
		buf[w] = '0';
		w++;
		buf[w] = '.';
		w++;
		w += digitZero(buf[w : w + -a.dp]);
		w += bytes.Copy(buf[w : w + a.nd], a.d[0 : a.nd]);

	case a.dp < a.nd:
		// decimal point in middle of digits
		w += bytes.Copy(buf[w : w + a.dp], a.d[0 : a.dp]);
		buf[w] = '.';
		w++;
		w += bytes.Copy(buf[w : w + a.nd - a.dp], a.d[a.dp : a.nd]);

	default:
		// zeros fill space between digits and decimal point
		w += bytes.Copy(buf[w : w + a.nd], a.d[0 : a.nd]);
		w += digitZero(buf[w : w + a.dp - a.nd]);
	}
	return string(buf[0:w]);
}

func copy(dst []byte, src []byte) int {
	for i := 0; i < len(dst); i++ {
		dst[i] = src[i]
	}
	return len(dst);
}

func digitZero(dst []byte) int {
	for i := 0; i < len(dst); i++ {
		dst[i] = '0'
	}
	return len(dst);
}

// trim trailing zeros from number.
// (They are meaningless; the decimal point is tracked
// independent of the number of digits.)
func trim(a *decimal) {
	for a.nd > 0 && a.d[a.nd - 1] == '0' {
		a.nd--
	}
	if a.nd == 0 {
		a.dp = 0
	}
}

// Assign v to a.
func (a *decimal) Assign(v uint64) {
	var buf [50]byte;

	// Write reversed decimal in buf.
	n := 0;
	for v > 0 {
		v1 := v/10;
		v -= 10*v1;
		buf[n] = byte(v+'0');
		n++;
		v = v1;
	}

	// Reverse again to produce forward decimal in a.d.
	a.nd = 0;
	for n--; n >= 0; n-- {
		a.d[a.nd] = buf[n];
		a.nd++;
	}
	a.dp = a.nd;
	trim(a);
}

func newDecimal(i uint64) *decimal {
	a := new(decimal);
	a.Assign(i);
	return a;
}

// Maximum shift that we can do in one pass without overflow.
// Signed int has 31 bits, and we have to be able to accomodate 9<<k.
const maxShift = 27

// Binary shift right (* 2) by k bits.  k <= maxShift to avoid overflow.
func rightShift(a *decimal, k uint) {
	r := 0;	// read pointer
	w := 0;	// write pointer

	// Pick up enough leading digits to cover first shift.
	n := 0;
	for ; n>>k == 0; r++ {
		if r >= a.nd {
			if n == 0 {
				// a == 0; shouldn't get here, but handle anyway.
				a.nd = 0;
				return;
			}
			for n>>k == 0 {
				n = n*10;
				r++;
			}
			break;
		}
		c := int(a.d[r]);
		n = n*10 + c - '0';
	}
	a.dp -= r-1;

	// Pick up a digit, put down a digit.
	for ; r < a.nd; r++ {
		c := int(a.d[r]);
		dig := n>>k;
		n -= dig<<k;
		a.d[w] = byte(dig+'0');
		w++;
		n = n*10 + c - '0';
	}

	// Put down extra digits.
	for n > 0 {
		dig := n>>k;
		n -= dig<<k;
		a.d[w] = byte(dig+'0');
		w++;
		n = n*10;
	}

	a.nd = w;
	trim(a);
}

// Cheat sheet for left shift: table indexed by shift count giving
// number of new digits that will be introduced by that shift.
//
// For example, leftcheats[4] = {2, "625"}.  That means that
// if we are shifting by 4 (multiplying by 16), it will add 2 digits
// when the string prefix is "625" through "999", and one fewer digit
// if the string prefix is "000" through "624".
//
// Credit for this trick goes to Ken.

type leftCheat struct {
	delta	int;	// number of new digits
	cutoff	string;	//   minus one digit if original < a.
}

var leftcheats = []leftCheat{
	// Leading digits of 1/2^i = 5^i.
	// 5^23 is not an exact 64-bit floating point number,
	// so have to use bc for the math.
	/*
		seq 27 | sed 's/^/5^/' | bc |
		awk 'BEGIN{ print "\tleftCheat{ 0, \"\" }," }
		{
			log2 = log(2)/log(10)
			printf("\tleftCheat{ %d, \"%s\" },\t// * %d\n",
				int(log2*NR+1), $0, 2**NR)
		}'
	*/
	leftCheat{0, ""},
	leftCheat{1, "5"},	// * 2
	leftCheat{1, "25"},	// * 4
	leftCheat{1, "125"},	// * 8
	leftCheat{2, "625"},	// * 16
	leftCheat{2, "3125"},	// * 32
	leftCheat{2, "15625"},	// * 64
	leftCheat{3, "78125"},	// * 128
	leftCheat{3, "390625"},	// * 256
	leftCheat{3, "1953125"},	// * 512
	leftCheat{4, "9765625"},	// * 1024
	leftCheat{4, "48828125"},	// * 2048
	leftCheat{4, "244140625"},	// * 4096
	leftCheat{4, "1220703125"},	// * 8192
	leftCheat{5, "6103515625"},	// * 16384
	leftCheat{5, "30517578125"},	// * 32768
	leftCheat{5, "152587890625"},	// * 65536
	leftCheat{6, "762939453125"},	// * 131072
	leftCheat{6, "3814697265625"},	// * 262144
	leftCheat{6, "19073486328125"},	// * 524288
	leftCheat{7, "95367431640625"},	// * 1048576
	leftCheat{7, "476837158203125"},	// * 2097152
	leftCheat{7, "2384185791015625"},	// * 4194304
	leftCheat{7, "11920928955078125"},	// * 8388608
	leftCheat{8, "59604644775390625"},	// * 16777216
	leftCheat{8, "298023223876953125"},	// * 33554432
	leftCheat{8, "1490116119384765625"},	// * 67108864
	leftCheat{9, "7450580596923828125"},	// * 134217728
}

// Is the leading prefix of b lexicographically less than s?
func prefixIsLessThan(b []byte, s string) bool {
	for i := 0; i < len(s); i++ {
		if i >= len(b) {
			return true
		}
		if b[i] != s[i] {
			return b[i] < s[i]
		}
	}
	return false;
}

// Binary shift left (/ 2) by k bits.  k <= maxShift to avoid overflow.
func leftShift(a *decimal, k uint) {
	delta := leftcheats[k].delta;
	if prefixIsLessThan(a.d[0 : a.nd], leftcheats[k].cutoff) {
		delta--
	}

	r := a.nd;		// read index
	w := a.nd + delta;	// write index
	n := 0;

	// Pick up a digit, put down a digit.
	for r--; r >= 0; r-- {
		n += (int(a.d[r])-'0')<<k;
		quo := n/10;
		rem := n - 10*quo;
		w--;
		a.d[w] = byte(rem+'0');
		n = quo;
	}

	// Put down extra digits.
	for n > 0 {
		quo := n/10;
		rem := n - 10*quo;
		w--;
		a.d[w] = byte(rem+'0');
		n = quo;
	}

	a.nd += delta;
	a.dp += delta;
	trim(a);
}

// Binary shift left (k > 0) or right (k < 0).
// Returns receiver for convenience.
func (a *decimal) Shift(k int) *decimal {
	switch {
	case a.nd == 0:
		// nothing to do: a == 0
	case k > 0:
		for k > maxShift {
			leftShift(a, maxShift);
			k -= maxShift;
		}
		leftShift(a, uint(k));
	case k < 0:
		for k < -maxShift {
			rightShift(a, maxShift);
			k += maxShift;
		}
		rightShift(a, uint(-k));
	}
	return a;
}

// If we chop a at nd digits, should we round up?
func shouldRoundUp(a *decimal, nd int) bool {
	if nd <= 0 || nd >= a.nd {
		return false
	}
	if a.d[nd] == '5' && nd+1 == a.nd {	// exactly halfway - round to even
		return (a.d[nd-1] - '0')%2 != 0
	}
	// not halfway - digit tells all
	return a.d[nd] >= '5';
}

// Round a to nd digits (or fewer).
// Returns receiver for convenience.
func (a *decimal) Round(nd int) *decimal {
	if nd <= 0 || nd >= a.nd {
		return a
	}
	if shouldRoundUp(a, nd) {
		return a.RoundUp(nd)
	}
	return a.RoundDown(nd);
}

// Round a down to nd digits (or fewer).
// Returns receiver for convenience.
func (a *decimal) RoundDown(nd int) *decimal {
	if nd <= 0 || nd >= a.nd {
		return a
	}
	a.nd = nd;
	trim(a);
	return a;
}

// Round a up to nd digits (or fewer).
// Returns receiver for convenience.
func (a *decimal) RoundUp(nd int) *decimal {
	if nd <= 0 || nd >= a.nd {
		return a
	}

	// round up
	for i := nd-1; i >= 0; i-- {
		c := a.d[i];
		if c < '9' {	// can stop after this digit
			a.d[i]++;
			a.nd = i+1;
			return a;
		}
	}

	// Number is all 9s.
	// Change to single 1 with adjusted decimal point.
	a.d[0] = '1';
	a.nd = 1;
	a.dp++;
	return a;
}

// Extract integer part, rounded appropriately.
// No guarantees about overflow.
func (a *decimal) RoundedInteger() uint64 {
	if a.dp > 20 {
		return 0xFFFFFFFFFFFFFFFF
	}
	var i int;
	n := uint64(0);
	for i = 0; i < a.dp && i < a.nd; i++ {
		n = n*10 + uint64(a.d[i] - '0')
	}
	for ; i < a.dp; i++ {
		n *= 10
	}
	if shouldRoundUp(a, a.dp) {
		n++
	}
	return n;
}