diff options
Diffstat (limited to 'vendor/modernc.org/mathutil/int.go')
-rw-r--r-- | vendor/modernc.org/mathutil/int.go | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/vendor/modernc.org/mathutil/int.go b/vendor/modernc.org/mathutil/int.go new file mode 100644 index 00000000..7c357876 --- /dev/null +++ b/vendor/modernc.org/mathutil/int.go @@ -0,0 +1,279 @@ +// Copyright (c) 2018 The mathutil Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package mathutil // import "modernc.org/mathutil" + +import ( + "fmt" + "math" + "math/big" +) + +var ( + // MaxInt128 represents the maximun Int128 value as big.Int + MaxInt128 *big.Int + // MinInt128 represents the minimun Int128 value as big.Int + MinInt128 *big.Int + // MaxUint128 represents the maximun Uint128 value as big.Int + MaxUint128 *big.Int +) + +func init() { + var ok bool + MaxInt128, ok = big.NewInt(0).SetString("0x7fffffff_ffffffff_ffffffff_ffffffff", 0) + if !ok { + panic("internal error") + } + + MinInt128 = big.NewInt(0).Set(MaxInt128) + MinInt128.Add(MinInt128, _1) + MinInt128.Neg(MinInt128) + + MaxUint128, ok = big.NewInt(0).SetString("0xffffffff_ffffffff_ffffffff_ffffffff", 0) + if !ok { + panic("internal error") + } +} + +const ( + maxInt128 = 1<<127 - 1 + maxUint128 = 1<<128 - 1 + minInt128 = -maxInt128 - 1 +) + +// Int128 is an 128 bit signed integer. +type Int128 struct { + Lo int64 // Bits 63..0. + Hi int64 // Bits 127..64. +} + +// Add returns the sum of x and y and a carry indication. +func (x Int128) Add(y Int128) (r Int128, cy bool) { + r.Lo = x.Lo + y.Lo + r.Hi = x.Hi + y.Hi + if uint64(r.Lo) < uint64(x.Lo) { + r.Hi++ + } + return r, (r.Cmp(x) < 0) == (y.Sign() >= 0) +} + +// BigInt returns x in the form of a big.Int. +func (x Int128) BigInt() *big.Int { + r := big.NewInt(x.Hi) + r.Lsh(r, 64) + lo := big.NewInt(0) + lo.SetUint64(uint64(x.Lo)) + return r.Add(r, lo) +} + +// Cmp compares x and y and returns: +// +// -1 if x < y +// 0 if x == y +// +1 if x > y +func (x Int128) Cmp(y Int128) int { + if x.Hi > y.Hi { + return 1 + } + + if x.Hi < y.Hi { + return -1 + } + + if uint64(x.Lo) > uint64(y.Lo) { + return 1 + } + + if uint64(x.Lo) < uint64(y.Lo) { + return -1 + } + + return 0 +} + +// Neg returns -x and an indication that x was not equal to MinInt128. +func (x Int128) Neg() (r Int128, ok bool) { + if x == (Int128{Hi: math.MinInt64}) { + return x, false + } + + x.Lo = ^x.Lo + x.Hi = ^x.Hi + r, _ = x.Add(Int128{Lo: 1}) + return r, true +} + +// SetBigInt sets x to y, returns x and an error, if any. +func (x *Int128) SetBigInt(y *big.Int) (r Int128, err error) { + if y.Cmp(MaxInt128) > 0 { + return *x, fmt.Errorf("%T.SetInt: overflow", x) + } + if y.Cmp(MinInt128) < 0 { + return *x, fmt.Errorf("%T.SetInt: underflow", x) + } + neg := y.Sign() < 0 + var z big.Int + z.Set(y) + if neg { + z.Neg(&z) + } + r.Lo = z.Int64() + z.Rsh(&z, 64) + r.Hi = z.Int64() + if neg { + r, _ = r.Neg() + } + *x = r + return r, nil +} + +// SetInt64 sets x to y and returns x. +func (x *Int128) SetInt64(y int64) (r Int128) { + r.Lo = y + if y >= 0 { + r.Hi = 0 + *x = r + return r + } + + r.Hi = -1 + *x = r + return r +} + +// SetUint64 sets x to y and returns x. +func (x *Int128) SetUint64(y uint64) (r Int128) { + r = Int128{Lo: int64(y)} + *x = r + return r +} + +// Sign returns: +// +// -1 if x < 0 +// 0 if x == 0 +// +1 if x > 0 +func (x Int128) Sign() int { + if x.Hi < 0 { + return -1 + } + + if x.Hi != 0 || x.Lo != 0 { + return 1 + } + + return 0 +} + +// String implements fmt.Stringer() +func (x Int128) String() string { return x.BigInt().String() } + +// NewInt128FromInt64 return a new Int128 value initialized to n. +func NewInt128FromInt64(n int64) (r Int128) { + r.Lo = n + if n < 0 { + r.Hi = -1 + } + return r +} + +// NewInt128FromUint64 return a new Int128 value initialized to n. +func NewInt128FromUint64(n uint64) (r Int128) { return Int128{Lo: int64(n)} } + +// NewInt128FromFloat32 returns a new Int128 value initialized to n. Result is +// not specified in n does not represent a number within the range of Int128 +// values. +func NewInt128FromFloat32(n float32) (r Int128) { + if n >= minInt128 && n <= maxInt128 { + if n >= math.MinInt64 && n <= math.MaxInt64 { + return NewInt128FromInt64(int64(n)) + } + + f := big.NewFloat(float64(n)) + bi, _ := f.Int(nil) + r.SetBigInt(bi) + } + return r +} + +// NewInt128FromFloat64 returns a new Int128 value initialized to n. Result is +// not specified in n does not represent a number within the range of Int128 +// values. +func NewInt128FromFloat64(n float64) (r Int128) { + if n >= minInt128 && n <= maxInt128 { + if n >= math.MinInt64 && n <= math.MaxInt64 { + return NewInt128FromInt64(int64(n)) + } + + f := big.NewFloat(n) + bi, _ := f.Int(nil) + r.SetBigInt(bi) + } + return r +} + +// Uint128 is an 128 bit unsigned integer. +type Uint128 struct { + Lo uint64 // Bits 63..0. + Hi uint64 // Bits 127..64. +} + +// NewUint128FromInt64 return a new Uint128 value initialized to n. +func NewUint128FromInt64(n int64) (r Uint128) { + r.Lo = uint64(n) + if n < 0 { + r.Hi = ^uint64(0) + } + return r +} + +// NewUint128FromUint64 return a new Uint128 value initialized to n. +func NewUint128FromUint64(n uint64) (r Uint128) { return Uint128{Lo: n} } + +// NewUint128FromFloat32 returns a new Uint128 value initialized to n. Result is +// not specified in n does not represent a number within the range of Uint128 +// values. +func NewUint128FromFloat32(n float32) (r Uint128) { + if n >= 0 { + if n <= math.MaxUint64 { + return NewUint128FromUint64(uint64(n)) + } + + f := big.NewFloat(float64(n)) + bi, _ := f.Int(nil) + r.SetBigInt(bi) + } + return r +} + +// NewUint128FromFloat64 returns a new Uint128 value initialized to n. Result is +// not specified in n does not represent a number within the range of Uint128 +// values. +func NewUint128FromFloat64(n float64) (r Uint128) { + if n >= 0 && n <= maxUint128 { + if n <= math.MaxUint64 { + return NewUint128FromUint64(uint64(n)) + } + + f := big.NewFloat(n) + bi, _ := f.Int(nil) + r.SetBigInt(bi) + } + return r +} + +// SetBigInt sets x to y, returns x and an error, if any. +func (x *Uint128) SetBigInt(y *big.Int) (r Uint128, err error) { + if y.Sign() < 0 || y.Cmp(MaxUint128) > 0 { + return *x, fmt.Errorf("%T.SetInt: overflow", x) + } + + var z big.Int + z.Set(y) + r.Lo = z.Uint64() + z.Rsh(&z, 64) + r.Hi = z.Uint64() + *x = r + return r, nil +} |