-
Notifications
You must be signed in to change notification settings - Fork 56
/
decimal.go
225 lines (215 loc) · 6.71 KB
/
decimal.go
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
// uint256: Fixed size 256-bit math library
// Copyright 2020 uint256 Authors
// SPDX-License-Identifier: BSD-3-Clause
package uint256
import (
"io"
"strconv"
)
const twoPow256Sub1 = "115792089237316195423570985008687907853269984665640564039457584007913129639935"
// Dec returns the decimal representation of z.
func (z *Int) Dec() string {
if z.IsZero() {
return "0"
}
if z.IsUint64() {
return strconv.FormatUint(z.Uint64(), 10)
}
// The max uint64 value being 18446744073709551615, the largest
// power-of-ten below that is 10000000000000000000.
// When we do a DivMod using that number, the remainder that we
// get back is the lower part of the output.
//
// The ascii-output of remainder will never exceed 19 bytes (since it will be
// below 10000000000000000000).
//
// Algorithm example using 100 as divisor
//
// 12345 % 100 = 45 (rem)
// 12345 / 100 = 123 (quo)
// -> output '45', continue iterate on 123
var (
// out is 98 bytes long: 78 (max size of a string without leading zeroes,
// plus slack so we can copy 19 bytes every iteration).
// We init it with zeroes, because when strconv appends the ascii representations,
// it will omit leading zeroes.
out = []byte("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
divisor = NewInt(10000000000000000000) // 20 digits
y = new(Int).Set(z) // copy to avoid modifying z
pos = len(out) // position to write to
buf = make([]byte, 0, 19) // buffer to write uint64:s to
)
for {
// Obtain Q and R for divisor
var quot, rem Int
udivrem(quot[:], y[:], divisor, &rem)
y.Set(") // Set Q for next loop
// Convert the R to ascii representation
buf = strconv.AppendUint(buf[:0], rem.Uint64(), 10)
// Copy in the ascii digits
copy(out[pos-len(buf):], buf)
if y.IsZero() {
break
}
// Move 19 digits left
pos -= 19
}
// skip leading zeroes by only using the 'used size' of buf
return string(out[pos-len(buf):])
}
// PrettyDec returns the decimal representation of z, with thousands-separators.
func (z *Int) PrettyDec(separator byte) string {
if z.IsZero() {
return "0"
}
// See algorithm-description in Dec()
// This just also inserts comma while copying byte-for-byte instead
// of using copy().
var (
out = []byte("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
divisor = NewInt(10000000000000000000)
y = new(Int).Set(z) // copy to avoid modifying z
pos = len(out) - 1 // position to write to
buf = make([]byte, 0, 19) // buffer to write uint64:s to
comma = 0
)
for {
var quot, rem Int
udivrem(quot[:], y[:], divisor, &rem)
y.Set(") // Set Q for next loop
buf = strconv.AppendUint(buf[:0], rem.Uint64(), 10)
for j := len(buf) - 1; j >= 0; j-- {
if comma == 3 {
out[pos] = separator
pos--
comma = 0
}
out[pos] = buf[j]
comma++
pos--
}
if y.IsZero() {
break
}
// Need to do zero-padding if we have more iterations coming
for j := 0; j < 19-len(buf); j++ {
if comma == 3 {
out[pos] = separator
pos--
comma = 0
}
comma++
pos--
}
}
return string(out[pos+1:])
}
// FromDecimal is a convenience-constructor to create an Int from a
// decimal (base 10) string. Numbers larger than 256 bits are not accepted.
func FromDecimal(decimal string) (*Int, error) {
var z Int
if err := z.SetFromDecimal(decimal); err != nil {
return nil, err
}
return &z, nil
}
// MustFromDecimal is a convenience-constructor to create an Int from a
// decimal (base 10) string.
// Returns a new Int and panics if any error occurred.
func MustFromDecimal(decimal string) *Int {
var z Int
if err := z.SetFromDecimal(decimal); err != nil {
panic(err)
}
return &z
}
// SetFromDecimal sets z from the given string, interpreted as a decimal number.
// OBS! This method is _not_ strictly identical to the (*big.Int).SetString(..., 10) method.
// Notable differences:
// - This method does not accept underscore input, e.g. "100_000",
// - This method does not accept negative zero as valid, e.g "-0",
// - (this method does not accept any negative input as valid))
func (z *Int) SetFromDecimal(s string) (err error) {
// Remove max one leading +
if len(s) > 0 && s[0] == '+' {
s = s[1:]
}
// Remove any number of leading zeroes
if len(s) > 0 && s[0] == '0' {
var i int
var c rune
for i, c = range s {
if c != '0' {
break
}
}
s = s[i:]
}
if len(s) < len(twoPow256Sub1) {
return z.fromDecimal(s)
}
if len(s) == len(twoPow256Sub1) {
if s > twoPow256Sub1 {
return ErrBig256Range
}
return z.fromDecimal(s)
}
return ErrBig256Range
}
// multipliers holds the values that are needed for fromDecimal
var multipliers = [5]*Int{
nil, // represents first round, no multiplication needed
{10000000000000000000, 0, 0, 0}, // 10 ^ 19
{687399551400673280, 5421010862427522170, 0, 0}, // 10 ^ 38
{5332261958806667264, 17004971331911604867, 2938735877055718769, 0}, // 10 ^ 57
{0, 8607968719199866880, 532749306367912313, 1593091911132452277}, // 10 ^ 76
}
// fromDecimal is a helper function to only ever be called via SetFromDecimal
// this function takes a string and chunks it up, calling ParseUint on it up to 5 times
// these chunks are then multiplied by the proper power of 10, then added together.
// Note: this method assumes that some basic validity-checks have already been performed
// on the input 'bs'. See SetFromDecimal.
func (z *Int) fromDecimal(bs string) error {
// first clear the input
z.Clear()
// the maximum value of uint64 is 18446744073709551615, which is 20 characters
// one less means that a string of 19 9's is always within the uint64 limit
var (
num uint64
err error
remaining = len(bs)
)
if remaining == 0 {
return io.EOF
}
// We proceed in steps of 19 characters (nibbles), from least significant to most significant.
// This means that the first (up to) 19 characters do not need to be multiplied.
// In the second iteration, our slice of 19 characters needs to be multipleied
// by a factor of 10^19. Et cetera.
for i, mult := range multipliers {
if remaining <= 0 {
return nil // Done
} else if remaining > 19 {
num, err = strconv.ParseUint(bs[remaining-19:remaining], 10, 64)
} else {
// Final round
num, err = strconv.ParseUint(bs, 10, 64)
}
if err != nil {
return err
}
// add that number to our running total
if i == 0 {
z.SetUint64(num)
} else {
base := NewInt(num)
z.Add(z, base.Mul(base, mult))
}
// Chop off another 19 characters
if remaining > 19 {
bs = bs[0 : remaining-19]
}
remaining -= 19
}
return nil
}