github.com/cznic/mathutil@v0.0.0-20181122101859-297441e03548/int.go (about) 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 6 7 import ( 8 "fmt" 9 "math" 10 "math/big" 11 ) 12 13 var ( 14 // The maximun Int128 value. 15 MaxInt128 *big.Int 16 // The minimun Int128 value. 17 MinInt128 *big.Int 18 ) 19 20 func init() { 21 MaxInt128 = big.NewInt(0) 22 MaxInt128.SetBit(MaxInt128, 127, 1) 23 MaxInt128.Sub(MaxInt128, _1) 24 MinInt128 = big.NewInt(0) 25 MinInt128.Set(MaxInt128) 26 MinInt128.Add(MinInt128, _1) 27 MinInt128.Neg(MinInt128) 28 } 29 30 // Int128 is an 128 bit integer. 31 type Int128 struct { 32 Lo int64 // Bits 63..0. 33 Hi int64 // Bits 127..64. 34 } 35 36 // Add returns the sum of x and y and a carry indication. 37 func (x Int128) Add(y Int128) (r Int128, cy bool) { 38 r.Lo = x.Lo + y.Lo 39 r.Hi = x.Hi + y.Hi 40 if uint64(r.Lo) < uint64(x.Lo) { 41 r.Hi++ 42 } 43 return r, (r.Cmp(x) < 0) == (y.Sign() >= 0) 44 } 45 46 // BigInt returns x in the form of a big.Int. 47 func (x Int128) BigInt() *big.Int { 48 r := big.NewInt(x.Hi) 49 r.Lsh(r, 64) 50 lo := big.NewInt(0) 51 lo.SetUint64(uint64(x.Lo)) 52 return r.Add(r, lo) 53 } 54 55 // Cmp compares x and y and returns: 56 // 57 // -1 if x < y 58 // 0 if x == y 59 // +1 if x > y 60 func (x Int128) Cmp(y Int128) int { 61 if x.Hi > y.Hi { 62 return 1 63 } 64 65 if x.Hi < y.Hi { 66 return -1 67 } 68 69 if uint64(x.Lo) > uint64(y.Lo) { 70 return 1 71 } 72 73 if uint64(x.Lo) < uint64(y.Lo) { 74 return -1 75 } 76 77 return 0 78 } 79 80 // Neg returns -x and an indication that x was not equal to MinInt128. 81 func (x Int128) Neg() (r Int128, ok bool) { 82 if x == (Int128{Hi: math.MinInt64}) { 83 return x, false 84 } 85 86 x.Lo = ^x.Lo 87 x.Hi = ^x.Hi 88 r, _ = x.Add(Int128{Lo: 1}) 89 return r, true 90 } 91 92 // SetBigInt sets x to y, returns x and an error, if any. 93 func (x *Int128) SetBigInt(y *big.Int) (r Int128, err error) { 94 if y.Cmp(MaxInt128) > 0 { 95 return *x, fmt.Errorf("%T.SetInt: overflow", x) 96 } 97 if y.Cmp(MinInt128) < 0 { 98 return *x, fmt.Errorf("%T.SetInt: underflow", x) 99 } 100 neg := y.Sign() < 0 101 var z big.Int 102 z.Set(y) 103 if neg { 104 z.Neg(&z) 105 } 106 r.Lo = z.Int64() 107 z.Rsh(&z, 64) 108 r.Hi = z.Int64() 109 if neg { 110 r, _ = r.Neg() 111 } 112 *x = r 113 return r, nil 114 } 115 116 // SetInt64 sets x to y and returns x. 117 func (x *Int128) SetInt64(y int64) (r Int128) { 118 r.Lo = y 119 if y >= 0 { 120 r.Hi = 0 121 *x = r 122 return r 123 } 124 125 r.Hi = -1 126 *x = r 127 return r 128 } 129 130 // SetInt64 sets x to y and returns x. 131 func (x *Int128) SetUint64(y uint64) (r Int128) { 132 r = Int128{Lo: int64(y)} 133 *x = r 134 return r 135 } 136 137 // Sign returns: 138 // 139 // -1 if x < 0 140 // 0 if x == 0 141 // +1 if x > 0 142 func (x Int128) Sign() int { 143 if x.Hi < 0 { 144 return -1 145 } 146 147 if x.Hi != 0 || x.Lo != 0 { 148 return 1 149 } 150 151 return 0 152 } 153 154 // String implements fmt.Stringer() 155 func (x Int128) String() string { return x.BigInt().String() }