我正在构建一个Lisp,如果计算会导致32位整数溢出,我希望它们自动转换为64位整数。同样地,对于64位溢出,也要切换到任意大小的整数。
我的问题是,我不知道检测整数溢出的“正确”方法是什么。
a, b := 2147483647, 2147483647
c := a + b
如何有效地检查 c 是否发生了溢出?
我考虑过始终将值转换为64位进行计算,然后在可能的情况下再次缩小大小,但这似乎对于像基本算术这样作为语言的基础和核心的东西来说过于昂贵且浪费内存。
我正在构建一个Lisp,如果计算会导致32位整数溢出,我希望它们自动转换为64位整数。同样地,对于64位溢出,也要切换到任意大小的整数。
我的问题是,我不知道检测整数溢出的“正确”方法是什么。
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
((c < a) != (b < 0))
,其中 c := a + b
。 - d11wtq对于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
}
Math.multiplyExact(int, int)
所做的。 - user2357112__builtin_add_overflow
,并且if(__builtin_add_overflow(a,b,c)) { ...
可以直接编译成一个add
和一个jo
或者其他给定平台的内容。 - hobbsmath.MinInt8 / -1
本身就会导致溢出。 - user539810