Checked integer arithmetic for Go. Prevents overflow, underflow, and division by zero by returning errors instead of wrapping or panicking.
go get github.com/Gustrb/checkedmathRequires Go 1.21+ (generics). Dependency: golang.org/x/exp (for constraints.Integer).
Use the pre-bound functions for standard types:
package main
import (
"fmt"
"github.com/Gustrb/checkedmath"
)
func main() {
// Addition — returns error on overflow
sum, err := checkedmath.Add64(100, 200)
if err != nil {
fmt.Println("overflow:", err)
return
}
fmt.Println(sum) // 300
// Division by zero
_, err = checkedmath.Div64(10, 0)
if err != nil {
fmt.Println(err) // division by zero
}
}Chain operations with the builder and check once at the end:
result, err := checkedmath.NewInt64(10).
Add(20).
Mul(3).
Div(2).
Result()
if err != nil {
return err // overflow or division by zero
}
// result == 45| Type | Add | Sub | Mul | Div | Builder | Constructor |
|---|---|---|---|---|---|---|
| int8 | Add8, Sub8, Mul8, Div8 | BuilderInt8 | NewInt8 | |||
| int16 | Add16, Sub16, Mul16, Div16 | BuilderInt16 | NewInt16 | |||
| int32 | Add32, Sub32, Mul32, Div32 | BuilderInt32 | NewInt32 | |||
| int64 | Add64, Sub64, Mul64, Div64 | BuilderInt64 | NewInt64 | |||
| uint8 | AddU8, SubU8, MulU8, DivU8 | BuilderUint8 | NewUint8 | |||
| uint16 | AddU16, SubU16, MulU16, DivU16 | BuilderUint16 | NewUint16 | |||
| uint32 | AddU32, SubU32, MulU32, DivU32 | BuilderUint32 | NewUint32 | |||
| uint64 | AddU64, SubU64, MulU64, DivU64 | BuilderUint64 | NewUint64 |
- Add / Sub / Mul: return
ErrOverflowwhen the result would exceed the type’s range (or underflow for unsigned Sub). - Div: returns
ErrDivisionByZerowhen the divisor is zero.
checkedmath.ErrOverflow— result would overflow (or underflow for unsigned subtraction).checkedmath.ErrDivisionByZero— division by zero.
Builders let you chain operations and handle a single error at the end. After an error, later steps are no-ops and the same error is returned from Result().
result, err := checkedmath.NewUint64(100).
Mul(3).
Div(2).
DivRounded(7).
Result()- DivRounded(n) — computes
(value + n/2) / n(rounded division). Still returnsErrDivisionByZeroifn == 0.
For custom ranges (e.g. clamped values), use the generic constructors:
BoundedAdd[T](upper, lower T) func(a, b T) (T, error)BoundedSub[T](upper, lower T) func(a, b T) (T, error)BoundedMul[T](upper, lower T) func(a, b T) (T, error)BoundedDiv[T](upper, lower T) func(a, b T) (T, error)
T must satisfy constraints.Integer. Example for int64 with standard range:
add := checkedmath.BoundedAdd[int64](math.MaxInt64, math.MinInt64)
sum, err := add(a, b)See repository.