// Copyright (c) 2014 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 provides utilities supplementing the standard 'math' and // 'math/rand' packages. // // Release history and compatibility issues // // 2020-12-20 v1.2.1 fixes MulOverflowInt64. // // 2020-12-19 Added {Add,Sub,Mul}OverflowInt{8,16,32,64} // // 2018-10-21 Added BinaryLog // // 2018-04-25: New functions for determining Max/Min of nullable values. Ex: // func MaxPtr(a, b *int) *int { // func MinPtr(a, b *int) *int { // func MaxBytePtr(a, b *byte) *byte { // func MinBytePtr(a, b *byte) *byte { // ... // // 2017-10-14: New variadic functions for Max/Min. Ex: // func MaxVal(val int, vals ...int) int { // func MinVal(val int, vals ...int) int { // func MaxByteVal(val byte, vals ...byte) byte { // func MinByteVal(val byte, vals ...byte) byte { // ... // // 2016-10-10: New functions QuadPolyDiscriminant and QuadPolyFactors. // // 2013-12-13: The following functions have been REMOVED // // func Uint64ToBigInt(n uint64) *big.Int // func Uint64FromBigInt(n *big.Int) (uint64, bool) // // 2013-05-13: The following functions are now DEPRECATED // // func Uint64ToBigInt(n uint64) *big.Int // func Uint64FromBigInt(n *big.Int) (uint64, bool) // // These functions will be REMOVED with Go release 1.1+1. // // 2013-01-21: The following functions have been REMOVED // // func MaxInt() int // func MinInt() int // func MaxUint() uint // func UintPtrBits() int // // They are now replaced by untyped constants // // MaxInt // MinInt // MaxUint // UintPtrBits // // Additionally one more untyped constant was added // // IntBits // // This change breaks any existing code depending on the above removed // functions. They should have not been published in the first place, that was // unfortunate. Instead, defining such architecture and/or implementation // specific integer limits and bit widths as untyped constants improves // performance and allows for static dead code elimination if it depends on // these values. Thanks to minux for pointing it out in the mail list // (https://groups.google.com/d/msg/golang-nuts/tlPpLW6aJw8/NT3mpToH-a4J). // // 2012-12-12: The following functions will be DEPRECATED with Go release // 1.0.3+1 and REMOVED with Go release 1.0.3+2, b/c of // http://code.google.com/p/go/source/detail?r=954a79ee3ea8 // // func Uint64ToBigInt(n uint64) *big.Int // func Uint64FromBigInt(n *big.Int) (uint64, bool)
package mathutil // import "modernc.org/mathutil" import ( ) // Architecture and/or implementation specific integer limits and bit widths. const ( MaxInt = 1<<(IntBits-1) - 1 MinInt = -MaxInt - 1 MaxUint = 1<<IntBits - 1 IntBits = 1 << (^uint(0)>>32&1 + ^uint(0)>>16&1 + ^uint(0)>>8&1 + 3) UintPtrBits = 1 << (^uintptr(0)>>32&1 + ^uintptr(0)>>16&1 + ^uintptr(0)>>8&1 + 3) ) var ( _1 = big.NewInt(1) _2 = big.NewInt(2) ) // GCDByte returns the greatest common divisor of a and b. Based on: // http://en.wikipedia.org/wiki/Euclidean_algorithm#Implementations func (, byte) byte { for != 0 { , = , % } return } // GCDUint16 returns the greatest common divisor of a and b. func (, uint16) uint16 { for != 0 { , = , % } return } // GCDUint32 returns the greatest common divisor of a and b. func (, uint32) uint32 { for != 0 { , = , % } return } // GCDUint64 returns the greatest common divisor of a and b. func (, uint64) uint64 { for != 0 { , = , % } return } // ISqrt returns floor(sqrt(n)). Typical run time is few hundreds of ns. func ( uint32) ( uint32) { if == 0 { return } if >= math.MaxUint16*math.MaxUint16 { return math.MaxUint16 } var , uint32 for = ; ; , = , { = ( + /) / 2 if == || == { break } } return } // SqrtUint64 returns floor(sqrt(n)). Typical run time is about 0.5 µs. func ( uint64) ( uint64) { if == 0 { return } if >= math.MaxUint32*math.MaxUint32 { return math.MaxUint32 } var , uint64 for = ; ; , = , { = ( + /) / 2 if == || == { break } } return } // SqrtBig returns floor(sqrt(n)). It panics on n < 0. func ( *big.Int) ( *big.Int) { switch .Sign() { case -1: panic(-1) case 0: return big.NewInt(0) } var , big.Int = big.NewInt(0) .SetBit(, .BitLen()/2+1, 1) for { .Rsh(.Add(, .Div(, )), 1) if .Cmp() == 0 || .Cmp(&) == 0 { break } .Set() .Set(&) } return } // Log2Byte returns log base 2 of n. It's the same as index of the highest // bit set in n. For n == 0 -1 is returned. func ( byte) int { return log2[] } // Log2Uint16 returns log base 2 of n. It's the same as index of the highest // bit set in n. For n == 0 -1 is returned. func ( uint16) int { if := >> 8; != 0 { return log2[] + 8 } return log2[] } // Log2Uint32 returns log base 2 of n. It's the same as index of the highest // bit set in n. For n == 0 -1 is returned. func ( uint32) int { if := >> 24; != 0 { return log2[] + 24 } if := >> 16; != 0 { return log2[] + 16 } if := >> 8; != 0 { return log2[] + 8 } return log2[] } // Log2Uint64 returns log base 2 of n. It's the same as index of the highest // bit set in n. For n == 0 -1 is returned. func ( uint64) int { if := >> 56; != 0 { return log2[] + 56 } if := >> 48; != 0 { return log2[] + 48 } if := >> 40; != 0 { return log2[] + 40 } if := >> 32; != 0 { return log2[] + 32 } if := >> 24; != 0 { return log2[] + 24 } if := >> 16; != 0 { return log2[] + 16 } if := >> 8; != 0 { return log2[] + 8 } return log2[] } // ModPowByte computes (b^e)%m. It panics for m == 0 || b == e == 0. // // See also: http://en.wikipedia.org/wiki/Modular_exponentiation#Right-to-left_binary_method func (, , byte) byte { if == 0 && == 0 { panic(0) } if == 1 { return 0 } := uint16(1) for , := uint16(), uint16(); > 0; , = *%, >>1 { if &1 == 1 { = * % } } return byte() } // ModPowUint16 computes (b^e)%m. It panics for m == 0 || b == e == 0. func (, , uint16) uint16 { if == 0 && == 0 { panic(0) } if == 1 { return 0 } := uint32(1) for , := uint32(), uint32(); > 0; , = *%, >>1 { if &1 == 1 { = * % } } return uint16() } // ModPowUint32 computes (b^e)%m. It panics for m == 0 || b == e == 0. func (, , uint32) uint32 { if == 0 && == 0 { panic(0) } if == 1 { return 0 } := uint64(1) for , := uint64(), uint64(); > 0; , = *%, >>1 { if &1 == 1 { = * % } } return uint32() } // ModPowUint64 computes (b^e)%m. It panics for m == 0 || b == e == 0. func (, , uint64) ( uint64) { if == 0 && == 0 { panic(0) } if == 1 { return 0 } return modPowBigInt(big.NewInt(0).SetUint64(), big.NewInt(0).SetUint64(), big.NewInt(0).SetUint64()).Uint64() } func (, , *big.Int) ( *big.Int) { = big.NewInt(1) for , := 0, .BitLen(); < ; ++ { if .Bit() != 0 { .Mod(.Mul(, ), ) } .Mod(.Mul(, ), ) } return } // ModPowBigInt computes (b^e)%m. Returns nil for e < 0. It panics for m == 0 || b == e == 0. func (, , *big.Int) ( *big.Int) { if .Sign() == 0 && .Sign() == 0 { panic(0) } if .Cmp(_1) == 0 { return big.NewInt(0) } if .Sign() < 0 { return } return modPowBigInt(big.NewInt(0).Set(), big.NewInt(0).Set(), ) } var uint64ToBigIntDelta big.Int func () { uint64ToBigIntDelta.SetBit(&uint64ToBigIntDelta, 63, 1) } var uintptrBits int func () { := uint64(math.MaxUint64) uintptrBits = BitLenUintptr(uintptr()) } // UintptrBits returns the bit width of an uintptr at the executing machine. func () int { return uintptrBits } // AddUint128_64 returns the uint128 sum of uint64 a and b. func (, uint64) ( uint64, uint64) { = + if < { = 1 } return , } // MulUint128_64 returns the uint128 bit product of uint64 a and b. func (, uint64) (, uint64) { /* 2^(2 W) ahi bhi + 2^W alo bhi + 2^W ahi blo + alo blo FEDCBA98 76543210 FEDCBA98 76543210 ---- alo*blo ---- ---- alo*bhi ---- ---- ahi*blo ---- ---- ahi*bhi ---- */ const = 32 const = 1<< - 1 , , , := >>, >>, &, & = * := * := * , := AddUint128_64(, <<) , := AddUint128_64(, <<) _, = AddUint128_64(*, >>+>>++) return } // PowerizeBigInt returns (e, p) such that e is the smallest number for which p // == b^e is greater or equal n. For n < 0 or b < 2 (0, nil) is returned. // // NOTE: Run time for large values of n (above about 2^1e6 ~= 1e300000) can be // significant and/or unacceptabe. For any smaller values of n the function // typically performs in sub second time. For "small" values of n (cca bellow // 2^1e3 ~= 1e300) the same can be easily below 10 µs. // // A special (and trivial) case of b == 2 is handled separately and performs // much faster. func (, *big.Int) ( uint32, *big.Int) { switch { case .Cmp(_2) < 0 || .Sign() < 0: return case .Sign() == 0 || .Cmp(_1) == 0: return 0, big.NewInt(1) case .Cmp(_2) == 0: = big.NewInt(0) = uint32(.BitLen() - 1) .SetBit(, int(), 1) if .Cmp() < 0 { .Mul(, _2) ++ } return } := .BitLen() := .BitLen() = big.NewInt(1) var , big.Int for { switch .Cmp() { case -1: := uint32(( - .BitLen()) / ) if == 0 { = 1 } += switch { case 1: .Mul(, ) default: .Set(_1) .Set() := for { if &1 != 0 { .Mul(&, &) } if >>= 1; == 0 { break } .Mul(&, &) } .Mul(, &) } case 0, 1: return } } } // PowerizeUint32BigInt returns (e, p) such that e is the smallest number for // which p == b^e is greater or equal n. For n < 0 or b < 2 (0, nil) is // returned. // // More info: see PowerizeBigInt. func ( uint32, *big.Int) ( uint32, *big.Int) { switch { case < 2 || .Sign() < 0: return case .Sign() == 0 || .Cmp(_1) == 0: return 0, big.NewInt(1) case == 2: = big.NewInt(0) = uint32(.BitLen() - 1) .SetBit(, int(), 1) if .Cmp() < 0 { .Mul(, _2) ++ } return } var big.Int .SetInt64(int64()) return PowerizeBigInt(&, ) } /* ProbablyPrimeUint32 returns true if n is prime or n is a pseudoprime to base a. It implements the Miller-Rabin primality test for one specific value of 'a' and k == 1. Wrt pseudocode shown at http://en.wikipedia.org/wiki/Miller-Rabin_primality_test#Algorithm_and_running_time Input: n > 3, an odd integer to be tested for primality; Input: k, a parameter that determines the accuracy of the test Output: composite if n is composite, otherwise probably prime write n − 1 as 2^s·d with d odd by factoring powers of 2 from n − 1 LOOP: repeat k times: pick a random integer a in the range [2, n − 2] x ← a^d mod n if x = 1 or x = n − 1 then do next LOOP for r = 1 .. s − 1 x ← x^2 mod n if x = 1 then return composite if x = n − 1 then do next LOOP return composite return probably prime ... this function behaves like passing 1 for 'k' and additionally a fixed/non-random 'a'. Otherwise it's the same algorithm. See also: http://mathworld.wolfram.com/Rabin-MillerStrongPseudoprimeTest.html */ func (, uint32) bool { , := -1, 0 for ; &1 == 0; , = >>1, +1 { } := uint64(ModPowUint32(, , )) if == 1 || uint32() == -1 { return true } for ; > 1; -- { if = * % uint64(); == 1 { return false } if uint32() == -1 { return true } } return false } // ProbablyPrimeUint64_32 returns true if n is prime or n is a pseudoprime to // base a. It implements the Miller-Rabin primality test for one specific value // of 'a' and k == 1. See also ProbablyPrimeUint32. func ( uint64, uint32) bool { , := -1, 0 for ; &1 == 0; , = >>1, +1 { } := ModPowUint64(uint64(), , ) if == 1 || == -1 { return true } , := big.NewInt(0).SetUint64(), big.NewInt(0).SetUint64() for ; > 1; -- { if = .Mod(.Mul(, ), ).Uint64(); == 1 { return false } if == -1 { return true } } return false } // ProbablyPrimeBigInt_32 returns true if n is prime or n is a pseudoprime to // base a. It implements the Miller-Rabin primality test for one specific value // of 'a' and k == 1. See also ProbablyPrimeUint32. func ( *big.Int, uint32) bool { var big.Int .Set() .Sub(&, _1) // d <- n-1 := 0 for ; .Bit() == 0; ++ { } := big.NewInt(0).Set(&) .Rsh(&, uint()) := ModPowBigInt(big.NewInt(int64()), &, ) if .Cmp(_1) == 0 || .Cmp() == 0 { return true } for ; > 1; -- { if = .Mod(.Mul(, ), ); .Cmp(_1) == 0 { return false } if .Cmp() == 0 { return true } } return false } // ProbablyPrimeBigInt returns true if n is prime or n is a pseudoprime to base // a. It implements the Miller-Rabin primality test for one specific value of // 'a' and k == 1. See also ProbablyPrimeUint32. func (, *big.Int) bool { var big.Int .Set() .Sub(&, _1) // d <- n-1 := 0 for ; .Bit() == 0; ++ { } := big.NewInt(0).Set(&) .Rsh(&, uint()) := ModPowBigInt(, &, ) if .Cmp(_1) == 0 || .Cmp() == 0 { return true } for ; > 1; -- { if = .Mod(.Mul(, ), ); .Cmp(_1) == 0 { return false } if .Cmp() == 0 { return true } } return false } // Max returns the larger of a and b. func (, int) int { if > { return } return } // Min returns the smaller of a and b. func (, int) int { if < { return } return } // MaxPtr returns a pointer to the larger of a and b, or nil. func (, *int) *int { if == nil { return } if == nil { return } if * > * { return } return } // MinPtr returns a pointer to the smaller of a and b, or nil. func (, *int) *int { if == nil { return } if == nil { return } if * < * { return } return } // MaxVal returns the largest argument passed. func ( int, ...int) int { := for , := range { if > { = } } return } // MinVal returns the smallest argument passed. func ( int, ...int) int { := for , := range { if < { = } } return } // Clamp returns a value restricted between lo and hi. func (, , int) int { return Min(Max(, ), ) } // UMax returns the larger of a and b. func (, uint) uint { if > { return } return } // UMin returns the smaller of a and b. func (, uint) uint { if < { return } return } // UMaxPtr returns a pointer to the larger of a and b, or nil. func (, *uint) *uint { if == nil { return } if == nil { return } if * > * { return } return } // UMinPtr returns a pointer to the smaller of a and b, or nil. func (, *uint) *uint { if == nil { return } if == nil { return } if * < * { return } return } // UMaxVal returns the largest argument passed. func ( uint, ...uint) uint { := for , := range { if > { = } } return } // UMinVal returns the smallest argument passed. func ( uint, ...uint) uint { := for , := range { if < { = } } return } // UClamp returns a value restricted between lo and hi. func (, , uint) uint { return UMin(UMax(, ), ) } // MaxByte returns the larger of a and b. func (, byte) byte { if > { return } return } // MinByte returns the smaller of a and b. func (, byte) byte { if < { return } return } // MaxBytePtr returns a pointer to the larger of a and b, or nil. func (, *byte) *byte { if == nil { return } if == nil { return } if * > * { return } return } // MinBytePtr returns a pointer to the smaller of a and b, or nil. func (, *byte) *byte { if == nil { return } if == nil { return } if * < * { return } return } // MaxByteVal returns the largest argument passed. func ( byte, ...byte) byte { := for , := range { if > { = } } return } // MinByteVal returns the smallest argument passed. func ( byte, ...byte) byte { := for , := range { if < { = } } return } // ClampByte returns a value restricted between lo and hi. func (, , byte) byte { return MinByte(MaxByte(, ), ) } // MaxInt8 returns the larger of a and b. func (, int8) int8 { if > { return } return } // MinInt8 returns the smaller of a and b. func (, int8) int8 { if < { return } return } // MaxInt8Ptr returns a pointer to the larger of a and b, or nil. func (, *int8) *int8 { if == nil { return } if == nil { return } if * > * { return } return } // MinInt8Ptr returns a pointer to the smaller of a and b, or nil. func (, *int8) *int8 { if == nil { return } if == nil { return } if * < * { return } return } // MaxInt8Val returns the largest argument passed. func ( int8, ...int8) int8 { := for , := range { if > { = } } return } // MinInt8Val returns the smallest argument passed. func ( int8, ...int8) int8 { := for , := range { if < { = } } return } // ClampInt8 returns a value restricted between lo and hi. func (, , int8) int8 { return MinInt8(MaxInt8(, ), ) } // MaxUint16 returns the larger of a and b. func (, uint16) uint16 { if > { return } return } // MinUint16 returns the smaller of a and b. func (, uint16) uint16 { if < { return } return } // MaxUint16Ptr returns a pointer to the larger of a and b, or nil. func (, *uint16) *uint16 { if == nil { return } if == nil { return } if * > * { return } return } // MinUint16Ptr returns a pointer to the smaller of a and b, or nil. func (, *uint16) *uint16 { if == nil { return } if == nil { return } if * < * { return } return } // MaxUint16Val returns the largest argument passed. func ( uint16, ...uint16) uint16 { := for , := range { if > { = } } return } // MinUint16Val returns the smallest argument passed. func ( uint16, ...uint16) uint16 { := for , := range { if < { = } } return } // ClampUint16 returns a value restricted between lo and hi. func (, , uint16) uint16 { return MinUint16(MaxUint16(, ), ) } // MaxInt16 returns the larger of a and b. func (, int16) int16 { if > { return } return } // MinInt16 returns the smaller of a and b. func (, int16) int16 { if < { return } return } // MaxInt16Ptr returns a pointer to the larger of a and b, or nil. func (, *int16) *int16 { if == nil { return } if == nil { return } if * > * { return } return } // MinInt16Ptr returns a pointer to the smaller of a and b, or nil. func (, *int16) *int16 { if == nil { return } if == nil { return } if * < * { return } return } // MaxInt16Val returns the largest argument passed. func ( int16, ...int16) int16 { := for , := range { if > { = } } return } // MinInt16Val returns the smallest argument passed. func ( int16, ...int16) int16 { := for , := range { if < { = } } return } // ClampInt16 returns a value restricted between lo and hi. func (, , int16) int16 { return MinInt16(MaxInt16(, ), ) } // MaxUint32 returns the larger of a and b. func (, uint32) uint32 { if > { return } return } // MinUint32 returns the smaller of a and b. func (, uint32) uint32 { if < { return } return } // MaxUint32Ptr returns a pointer to the larger of a and b, or nil. func (, *uint32) *uint32 { if == nil { return } if == nil { return } if * > * { return } return } // MinUint32Ptr returns a pointer to the smaller of a and b, or nil. func (, *uint32) *uint32 { if == nil { return } if == nil { return } if * < * { return } return } // MaxUint32Val returns the largest argument passed. func ( uint32, ...uint32) uint32 { := for , := range { if > { = } } return } // MinUint32Val returns the smallest argument passed. func ( uint32, ...uint32) uint32 { := for , := range { if < { = } } return } // ClampUint32 returns a value restricted between lo and hi. func (, , uint32) uint32 { return MinUint32(MaxUint32(, ), ) } // MaxInt32 returns the larger of a and b. func (, int32) int32 { if > { return } return } // MinInt32 returns the smaller of a and b. func (, int32) int32 { if < { return } return } // MaxInt32Ptr returns a pointer to the larger of a and b, or nil. func (, *int32) *int32 { if == nil { return } if == nil { return } if * > * { return } return } // MinInt32Ptr returns a pointer to the smaller of a and b, or nil. func (, *int32) *int32 { if == nil { return } if == nil { return } if * < * { return } return } // MaxInt32Val returns the largest argument passed. func ( int32, ...int32) int32 { := for , := range { if > { = } } return } // MinInt32Val returns the smallest argument passed. func ( int32, ...int32) int32 { := for , := range { if < { = } } return } // ClampInt32 returns a value restricted between lo and hi. func (, , int32) int32 { return MinInt32(MaxInt32(, ), ) } // MaxUint64 returns the larger of a and b. func (, uint64) uint64 { if > { return } return } // MinUint64 returns the smaller of a and b. func (, uint64) uint64 { if < { return } return } // MaxUint64Ptr returns a pointer to the larger of a and b, or nil. func (, *uint64) *uint64 { if == nil { return } if == nil { return } if * > * { return } return } // MinUint64Ptr returns a pointer to the smaller of a and b, or nil. func (, *uint64) *uint64 { if == nil { return } if == nil { return } if * < * { return } return } // MaxUint64Val returns the largest argument passed. func ( uint64, ...uint64) uint64 { := for , := range { if > { = } } return } // MinUint64Val returns the smallest argument passed. func ( uint64, ...uint64) uint64 { := for , := range { if < { = } } return } // ClampUint64 returns a value restricted between lo and hi. func (, , uint64) uint64 { return MinUint64(MaxUint64(, ), ) } // MaxInt64 returns the larger of a and b. func (, int64) int64 { if > { return } return } // MinInt64 returns the smaller of a and b. func (, int64) int64 { if < { return } return } // MaxInt64Ptr returns a pointer to the larger of a and b, or nil. func (, *int64) *int64 { if == nil { return } if == nil { return } if * > * { return } return } // MinInt64Ptr returns a pointer to the smaller of a and b, or nil. func (, *int64) *int64 { if == nil { return } if == nil { return } if * < * { return } return } // MaxInt64Val returns the largest argument passed. func ( int64, ...int64) int64 { := for , := range { if > { = } } return } // MinInt64Val returns the smallest argument passed. func ( int64, ...int64) int64 { := for , := range { if < { = } } return } // ClampInt64 returns a value restricted between lo and hi. func (, , int64) int64 { return MinInt64(MaxInt64(, ), ) } // ToBase produces n in base b. For example // // ToBase(2047, 22) -> [1, 5, 4] // // 1 * 22^0 1 // 5 * 22^1 110 // 4 * 22^2 1936 // ---- // 2047 // // ToBase panics for bases < 2. func ( *big.Int, int) []int { var big.Int .Set() if < 2 { panic("invalid base") } := 1 switch .Sign() { case -1: .Neg(&) = -1 case 0: return []int{0} } := big.NewInt(int64()) var []int := big.NewInt(0) for .Sign() != 0 { .QuoRem(&, , ) = append(, *int(.Int64())) } return } // CheckAddInt64 returns the a+b and an indicator that the result is greater // than math.MaxInt64. func (, int64) ( int64, bool) { return + , > 0 && > math.MaxInt64- || < 0 && < math.MinInt64- } // CheckSubInt64 returns a-b and an indicator that the result is less than than // math.MinInt64. func (, int64) ( int64, bool) { return - , > 0 && -math.MaxInt64 > || < 0 && -math.MinInt64 < } // AddOverflowInt8 returns a + b and an indication whether the addition // overflowed the int8 range. func (, int8) ( int8, bool) { = + if > 0 && > 0 { return , uint8() > math.MaxInt8 } if < 0 && < 0 { return , uint8() <= math.MaxInt8 } return , false } // AddOverflowInt16 returns a + b and an indication whether the addition // overflowed the int16 range. func (, int16) ( int16, bool) { = + if > 0 && > 0 { return , uint16() > math.MaxInt16 } if < 0 && < 0 { return , uint16() <= math.MaxInt16 } return , false } // AddOverflowInt32 returns a + b and an indication whether the addition // overflowed the int32 range. func (, int32) ( int32, bool) { = + if > 0 && > 0 { return , uint32() > math.MaxInt32 } if < 0 && < 0 { return , uint32() <= math.MaxInt32 } return , false } // AddOverflowInt64 returns a + b and an indication whether the addition // overflowed the int64 range. func (, int64) ( int64, bool) { = + if > 0 && > 0 { return , uint64() > math.MaxInt64 } if < 0 && < 0 { return , uint64() <= math.MaxInt64 } return , false } // SubOverflowInt8 returns a - b and an indication whether the subtraction // overflowed the int8 range. func (, int8) ( int8, bool) { = - if >= 0 && < 0 { return , uint8() >= math.MaxInt8+1 } if < 0 && > 0 { return , uint8() <= math.MaxInt8 } return , false } // SubOverflowInt16 returns a - b and an indication whether the subtraction // overflowed the int16 range. func (, int16) ( int16, bool) { = - if >= 0 && < 0 { return , uint16() >= math.MaxInt16+1 } if < 0 && > 0 { return , uint16() <= math.MaxInt16 } return , false } // SubOverflowInt32 returns a - b and an indication whether the subtraction // overflowed the int32 range. func (, int32) ( int32, bool) { = - if >= 0 && < 0 { return , uint32() >= math.MaxInt32+1 } if < 0 && > 0 { return , uint32() <= math.MaxInt32 } return , false } // SubOverflowInt64 returns a - b and an indication whether the subtraction // overflowed the int64 range. func (, int64) ( int64, bool) { = - if >= 0 && < 0 { return , uint64() >= math.MaxInt64+1 } if < 0 && > 0 { return , uint64() <= math.MaxInt64 } return , false } // MulOverflowInt8 returns a * b and an indication whether the product // overflowed the int8 range. func (, int8) ( int8, bool) { if == 0 || == 0 { return 0, false } := int16() * int16() return int8(), < math.MinInt8 || > math.MaxInt8 } // MulOverflowInt16 returns a * b and an indication whether the product // overflowed the int16 range. func (, int16) ( int16, bool) { if == 0 || == 0 { return 0, false } := int32() * int32() return int16(), < math.MinInt16 || > math.MaxInt16 } // MulOverflowInt32 returns a * b and an indication whether the product // overflowed the int32 range. func (, int32) ( int32, bool) { if == 0 || == 0 { return 0, false } := int64() * int64() return int32(), < math.MinInt32 || > math.MaxInt32 } // MulOverflowInt64 returns a * b and an indication whether the product // overflowed the int64 range. func (, int64) ( int64, bool) { // https://groups.google.com/g/golang-nuts/c/h5oSN5t3Au4/m/KaNQREhZh0QJ const = 1<<63 - 1 const = -( + 1) = * if == 0 || == 0 || == 1 || == 1 { return , false } if == || == { return , true } return , / != }