检测Go中的signed signed overflow溢出

时间:2015-11-10 23:37:01

标签: go integer-overflow

我正构建一个Lisp,如果计算会导致它们溢出,我希望32位整数自动切换到64位整数。同样,对于64位溢出,切换到任意大小的整数。

我遇到的问题是我不知道"纠正"方法是检测整数溢出。

a, b := 2147483647, 2147483647
c := a + b

如何有效地检查c是否溢出?

我已经考虑过总是转换为64位值来进行计算,然后在可能的情况下再次调整大小,但这对于像基本算术一样原始和核心的东西来说似乎很昂贵且浪费内存。

2 个答案:

答案 0 :(得分:8)

例如,要检测添加的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

答案 1 :(得分:1)

对于 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
}
  1. https://github.com/golang/go/blob/go1.16.3/src/math/bits/bits.go#L368-L373
  2. https://github.com/golang/go/blob/go1.16.3/src/math/bits/bits.go#L380-L387