在 Go 中检测有符号整数溢出
Detect signed int overflow in Go
我正在构建一个 Lisp,我希望 32 位整数在计算导致它们溢出时自动切换到 64 位整数。同样,对于 64 位溢出,切换到任意大小的整数。
我遇到的问题是我不知道 "correct" 检测整数溢出的方法是什么。
a, b := 2147483647, 2147483647
c := a + b
如何有效地检查 c 是否溢出?
我考虑过总是转换为 64 位值来进行计算,然后在可能的情况下再次缩小尺寸,但是对于像基本算术这样语言的原始和核心的东西来说,这似乎很昂贵并且浪费内存。
例如检测32位整数加法溢出,
package main
import (
"errors"
"fmt"
"math"
)
var ErrOverflow = errors.New("integer overflow")
func Add32(left, right int32) (int32, error) {
if right > 0 {
if left > math.MaxInt32-right {
return 0, ErrOverflow
}
} else {
if left < math.MinInt32-right {
return 0, ErrOverflow
}
}
return left + right, nil
}
func main() {
var a, b int32 = 2147483327, 2147483327
c, err := Add32(a, b)
if err != nil {
// handle overflow
fmt.Println(err, a, b, c)
}
}
输出:
integer overflow 2147483327 2147483327 0
对于 32 位整数,标准方法如您所说,转换为 64 位,然后再次缩小 [1]:
package main
func add32(x, y int32) (int32, int32) {
sum64 := int64(x) + int64(y)
return x + y, int32(sum64 >> 31)
}
func main() {
{
s, c := add32(2147483646, 1)
println(s == 2147483647, c == 0)
}
{
s, c := add32(2147483647, 1)
println(s == -2147483648, c == 1)
}
}
但是如果你不喜欢那样,你可以使用一些位操作[2]:
func add32(x, y int32) (int32, int32) {
sum := x + y
return sum, x & y | (x | y) &^ sum >> 30
}
我正在构建一个 Lisp,我希望 32 位整数在计算导致它们溢出时自动切换到 64 位整数。同样,对于 64 位溢出,切换到任意大小的整数。
我遇到的问题是我不知道 "correct" 检测整数溢出的方法是什么。
a, b := 2147483647, 2147483647
c := a + b
如何有效地检查 c 是否溢出?
我考虑过总是转换为 64 位值来进行计算,然后在可能的情况下再次缩小尺寸,但是对于像基本算术这样语言的原始和核心的东西来说,这似乎很昂贵并且浪费内存。
例如检测32位整数加法溢出,
package main
import (
"errors"
"fmt"
"math"
)
var ErrOverflow = errors.New("integer overflow")
func Add32(left, right int32) (int32, error) {
if right > 0 {
if left > math.MaxInt32-right {
return 0, ErrOverflow
}
} else {
if left < math.MinInt32-right {
return 0, ErrOverflow
}
}
return left + right, nil
}
func main() {
var a, b int32 = 2147483327, 2147483327
c, err := Add32(a, b)
if err != nil {
// handle overflow
fmt.Println(err, a, b, c)
}
}
输出:
integer overflow 2147483327 2147483327 0
对于 32 位整数,标准方法如您所说,转换为 64 位,然后再次缩小 [1]:
package main
func add32(x, y int32) (int32, int32) {
sum64 := int64(x) + int64(y)
return x + y, int32(sum64 >> 31)
}
func main() {
{
s, c := add32(2147483646, 1)
println(s == 2147483647, c == 0)
}
{
s, c := add32(2147483647, 1)
println(s == -2147483648, c == 1)
}
}
但是如果你不喜欢那样,你可以使用一些位操作[2]:
func add32(x, y int32) (int32, int32) {
sum := x + y
return sum, x & y | (x | y) &^ sum >> 30
}