23

I'm building a Lisp, and I want 32 bit integers to automatically switch to 64 bit integers if a computation would cause them to otherwise overflow. And likewise, for 64 bit overflows, switch to arbitrarily sized integers.

The problem I have is that I don't know what the "correct" way is to detect an integer overflow.

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

How can I efficiently check if c overflowed?

I have considered always converting to 64 bit values to do the calculation, then down-sizing again afterwards when possible, but that seems expensive and memory wasteful for something that is as primitive and core to the language as basic arithmetic.

6
  • I suspect boxing up is your best bet. There is no mechanism in the language precisely to keep addition fast. Commented Nov 10, 2015 at 23:43
  • 1
    I think the extra 4 bytes is near negligible in most modern systems to just use 64bit vs 32bit integers in most situations (exceptions made for large arrays, etc). As for runtime automatic detection of overflow without resorting to assembly, and if your environment doesn't throw an exception you can catch, it isn't trivial. IMHO. Commented Nov 10, 2015 at 23:44
  • Converting to 64-bit just for the calculation has essentially no memory impact, since you're only holding a constant number of up-sized values at a time. This is what, for example, OpenJDK's Math.multiplyExact(int, int) does. Commented Nov 11, 2015 at 3:33
  • 2
    @captncraig it could be done with no overhead (except slightly uglier code). The processor already computes the overflow bit on every single addition, for free; all you need is a way to tell the compiler you're interested in it. GCC has __builtin_add_overflow these days, and if(__builtin_add_overflow(a,b,c)) { ... can compile right down to an add and a jo, or whatever for a given platform. Commented Nov 11, 2015 at 4:22
  • @d11wtq honestly the reasonable thing to do here is to go 64-bit all the time. 32-bit CPUs are disappearing pretty quickly, and on a 64-bit machine there's no CPU cost to using 64-bit ints, and the memory cost is probably insignificant next to the overhead of other parts of your system. Commented Nov 11, 2015 at 4:26

2 Answers 2

19

For example, to detect 32-bit integer overflow for addition,

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)
    }
}

Output:

integer overflow 2147483327 2147483327 0
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! I think I might have a shorter solution, but not sure if there are edge cases where it doesn't work: ((c < a) != (b < 0)), where c := a + b.
2

For 32 bit integers, the standard way is as you said, to cast to 64 bit, then down size again [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)
   }
}

However if you don't like that, you can use some bit operations [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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.