source: code/trunk/vendor/modernc.org/mathutil/int.go@ 822

Last change on this file since 822 was 822, checked in by yakumo.izuru, 22 months ago

Prefer immortal.run over runit and rc.d, use vendored modules
for convenience.

Signed-off-by: Izuru Yakumo <yakumo.izuru@…>

File size: 5.8 KB
Line 
1// Copyright (c) 2018 The mathutil Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package mathutil // import "modernc.org/mathutil"
6
7import (
8 "fmt"
9 "math"
10 "math/big"
11)
12
13var (
14 // MaxInt128 represents the maximun Int128 value as big.Int
15 MaxInt128 *big.Int
16 // MinInt128 represents the minimun Int128 value as big.Int
17 MinInt128 *big.Int
18 // MaxUint128 represents the maximun Uint128 value as big.Int
19 MaxUint128 *big.Int
20)
21
22func init() {
23 var ok bool
24 MaxInt128, ok = big.NewInt(0).SetString("0x7fffffff_ffffffff_ffffffff_ffffffff", 0)
25 if !ok {
26 panic("internal error")
27 }
28
29 MinInt128 = big.NewInt(0).Set(MaxInt128)
30 MinInt128.Add(MinInt128, _1)
31 MinInt128.Neg(MinInt128)
32
33 MaxUint128, ok = big.NewInt(0).SetString("0xffffffff_ffffffff_ffffffff_ffffffff", 0)
34 if !ok {
35 panic("internal error")
36 }
37}
38
39const (
40 maxInt128 = 1<<127 - 1
41 maxUint128 = 1<<128 - 1
42 minInt128 = -maxInt128 - 1
43)
44
45// Int128 is an 128 bit signed integer.
46type Int128 struct {
47 Lo int64 // Bits 63..0.
48 Hi int64 // Bits 127..64.
49}
50
51// Add returns the sum of x and y and a carry indication.
52func (x Int128) Add(y Int128) (r Int128, cy bool) {
53 r.Lo = x.Lo + y.Lo
54 r.Hi = x.Hi + y.Hi
55 if uint64(r.Lo) < uint64(x.Lo) {
56 r.Hi++
57 }
58 return r, (r.Cmp(x) < 0) == (y.Sign() >= 0)
59}
60
61// BigInt returns x in the form of a big.Int.
62func (x Int128) BigInt() *big.Int {
63 r := big.NewInt(x.Hi)
64 r.Lsh(r, 64)
65 lo := big.NewInt(0)
66 lo.SetUint64(uint64(x.Lo))
67 return r.Add(r, lo)
68}
69
70// Cmp compares x and y and returns:
71//
72// -1 if x < y
73// 0 if x == y
74// +1 if x > y
75func (x Int128) Cmp(y Int128) int {
76 if x.Hi > y.Hi {
77 return 1
78 }
79
80 if x.Hi < y.Hi {
81 return -1
82 }
83
84 if uint64(x.Lo) > uint64(y.Lo) {
85 return 1
86 }
87
88 if uint64(x.Lo) < uint64(y.Lo) {
89 return -1
90 }
91
92 return 0
93}
94
95// Neg returns -x and an indication that x was not equal to MinInt128.
96func (x Int128) Neg() (r Int128, ok bool) {
97 if x == (Int128{Hi: math.MinInt64}) {
98 return x, false
99 }
100
101 x.Lo = ^x.Lo
102 x.Hi = ^x.Hi
103 r, _ = x.Add(Int128{Lo: 1})
104 return r, true
105}
106
107// SetBigInt sets x to y, returns x and an error, if any.
108func (x *Int128) SetBigInt(y *big.Int) (r Int128, err error) {
109 if y.Cmp(MaxInt128) > 0 {
110 return *x, fmt.Errorf("%T.SetInt: overflow", x)
111 }
112 if y.Cmp(MinInt128) < 0 {
113 return *x, fmt.Errorf("%T.SetInt: underflow", x)
114 }
115 neg := y.Sign() < 0
116 var z big.Int
117 z.Set(y)
118 if neg {
119 z.Neg(&z)
120 }
121 r.Lo = z.Int64()
122 z.Rsh(&z, 64)
123 r.Hi = z.Int64()
124 if neg {
125 r, _ = r.Neg()
126 }
127 *x = r
128 return r, nil
129}
130
131// SetInt64 sets x to y and returns x.
132func (x *Int128) SetInt64(y int64) (r Int128) {
133 r.Lo = y
134 if y >= 0 {
135 r.Hi = 0
136 *x = r
137 return r
138 }
139
140 r.Hi = -1
141 *x = r
142 return r
143}
144
145// SetUint64 sets x to y and returns x.
146func (x *Int128) SetUint64(y uint64) (r Int128) {
147 r = Int128{Lo: int64(y)}
148 *x = r
149 return r
150}
151
152// Sign returns:
153//
154// -1 if x < 0
155// 0 if x == 0
156// +1 if x > 0
157func (x Int128) Sign() int {
158 if x.Hi < 0 {
159 return -1
160 }
161
162 if x.Hi != 0 || x.Lo != 0 {
163 return 1
164 }
165
166 return 0
167}
168
169// String implements fmt.Stringer()
170func (x Int128) String() string { return x.BigInt().String() }
171
172// NewInt128FromInt64 return a new Int128 value initialized to n.
173func NewInt128FromInt64(n int64) (r Int128) {
174 r.Lo = n
175 if n < 0 {
176 r.Hi = -1
177 }
178 return r
179}
180
181// NewInt128FromUint64 return a new Int128 value initialized to n.
182func NewInt128FromUint64(n uint64) (r Int128) { return Int128{Lo: int64(n)} }
183
184// NewInt128FromFloat32 returns a new Int128 value initialized to n. Result is
185// not specified in n does not represent a number within the range of Int128
186// values.
187func NewInt128FromFloat32(n float32) (r Int128) {
188 if n >= minInt128 && n <= maxInt128 {
189 if n >= math.MinInt64 && n <= math.MaxInt64 {
190 return NewInt128FromInt64(int64(n))
191 }
192
193 f := big.NewFloat(float64(n))
194 bi, _ := f.Int(nil)
195 r.SetBigInt(bi)
196 }
197 return r
198}
199
200// NewInt128FromFloat64 returns a new Int128 value initialized to n. Result is
201// not specified in n does not represent a number within the range of Int128
202// values.
203func NewInt128FromFloat64(n float64) (r Int128) {
204 if n >= minInt128 && n <= maxInt128 {
205 if n >= math.MinInt64 && n <= math.MaxInt64 {
206 return NewInt128FromInt64(int64(n))
207 }
208
209 f := big.NewFloat(n)
210 bi, _ := f.Int(nil)
211 r.SetBigInt(bi)
212 }
213 return r
214}
215
216// Uint128 is an 128 bit unsigned integer.
217type Uint128 struct {
218 Lo uint64 // Bits 63..0.
219 Hi uint64 // Bits 127..64.
220}
221
222// NewUint128FromInt64 return a new Uint128 value initialized to n.
223func NewUint128FromInt64(n int64) (r Uint128) {
224 r.Lo = uint64(n)
225 if n < 0 {
226 r.Hi = ^uint64(0)
227 }
228 return r
229}
230
231// NewUint128FromUint64 return a new Uint128 value initialized to n.
232func NewUint128FromUint64(n uint64) (r Uint128) { return Uint128{Lo: n} }
233
234// NewUint128FromFloat32 returns a new Uint128 value initialized to n. Result is
235// not specified in n does not represent a number within the range of Uint128
236// values.
237func NewUint128FromFloat32(n float32) (r Uint128) {
238 if n >= 0 {
239 if n <= math.MaxUint64 {
240 return NewUint128FromUint64(uint64(n))
241 }
242
243 f := big.NewFloat(float64(n))
244 bi, _ := f.Int(nil)
245 r.SetBigInt(bi)
246 }
247 return r
248}
249
250// NewUint128FromFloat64 returns a new Uint128 value initialized to n. Result is
251// not specified in n does not represent a number within the range of Uint128
252// values.
253func NewUint128FromFloat64(n float64) (r Uint128) {
254 if n >= 0 && n <= maxUint128 {
255 if n <= math.MaxUint64 {
256 return NewUint128FromUint64(uint64(n))
257 }
258
259 f := big.NewFloat(n)
260 bi, _ := f.Int(nil)
261 r.SetBigInt(bi)
262 }
263 return r
264}
265
266// SetBigInt sets x to y, returns x and an error, if any.
267func (x *Uint128) SetBigInt(y *big.Int) (r Uint128, err error) {
268 if y.Sign() < 0 || y.Cmp(MaxUint128) > 0 {
269 return *x, fmt.Errorf("%T.SetInt: overflow", x)
270 }
271
272 var z big.Int
273 z.Set(y)
274 r.Lo = z.Uint64()
275 z.Rsh(&z, 64)
276 r.Hi = z.Uint64()
277 *x = r
278 return r, nil
279}
Note: See TracBrowser for help on using the repository browser.