Detect signed int overflow in Go

11,132

Solution 1

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

Solution 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
Share:
11,132
d11wtq
Author by

d11wtq

About me I'm a developer in various languages, but most notably Ruby and PHP, shifting more and more in the Ruby direction every day. I also enjoy playing around with Cocoa on OS X and iOS, but I don't pretend to be an expert. I have a half-written multi-language text editor in it. One day I may finish it, though I'm considering writing an Emacs-inspired terminal-based editor in Ruby instead. Employment Flippa.com Pty. Ltd, Melbourne (scroll down for opportunities) Main technologies: PHP, quickly &amp; iteratively moving to Ruby, Rails, DataMapper. I'm the development manager at Flippa.com and spend a lot of time working on stuff for them in my own time, mostly because I love it. We are currently in a long-term transitional period, migrating our codebase from a bespoke PHP framework to Ruby on Rails. Seamlessly running the two applications side-by-side poses some interesting problems. Our biggest ongoing technical challenges revolve around search infrastructure and a fairly complex and ever-evolving bidding system, along with tight integration with many external services. We spend a large amount of time re-thinking and improving our server infrastructure. We love exploring new technologies, where they actually make good sense as far as our needs are concerned. Job Opportunities If you're based in Australia and looking to work in a fun startup environment (we're about 3 years old) in Melbourne, drop me a note either on Twitter (@d11wtq), or via my github profile and we can arrange an interview if we think you're a good fit. We're always looking for technically-capable junior backend-developers/graduates, experienced backend-developers, and (at the current time) client-side developers. People who work with us love the atmosphere. We work in a lively office, shared with our sibling companies (SitePoint.com, 99designs.com, wavedigital.com.au and learnable.com). We have flexible working hours, a fridge full of beer and a foosball table. At the end of every year we all go away together and celebrate in style. Developers are also given the last 3 days in each month to work on projects of their own choosing. Open Source I have a selection of open source projects up on github (@d11wtq). Flippa also likes to share (@flippa).

Updated on June 06, 2022

Comments

  • d11wtq
    d11wtq about 2 years

    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.

  • d11wtq
    d11wtq over 8 years
    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.