int.go (5897B)
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 5 package mathutil // import "modernc.org/mathutil" 6 7 import ( 8 "fmt" 9 "math" 10 "math/big" 11 ) 12 13 var ( 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 22 func 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 39 const ( 40 maxInt128 = 1<<127 - 1 41 maxUint128 = 1<<128 - 1 42 minInt128 = -maxInt128 - 1 43 ) 44 45 // Int128 is an 128 bit signed integer. 46 type 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. 52 func (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. 62 func (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 75 func (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. 96 func (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. 108 func (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. 132 func (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. 146 func (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 157 func (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() 170 func (x Int128) String() string { return x.BigInt().String() } 171 172 // NewInt128FromInt64 return a new Int128 value initialized to n. 173 func 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. 182 func 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. 187 func 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. 203 func 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. 217 type 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. 223 func 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. 232 func 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. 237 func 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. 253 func 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. 267 func (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 }