// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved. // See the file LICENSE for licensing terms. package math import ( "errors" "golang.org/x/exp/constraints" ) var ( ErrOverflow = errors.New("overflow") ErrUnderflow = errors.New("underflow") // Deprecated: Add64 is deprecated. Use Add[uint64] instead. Add64 = Add[uint64] // Deprecated: Mul64 is deprecated. Use Mul[uint64] instead. Mul64 = Mul[uint64] ) // MaxUint returns the maximum value of an unsigned integer of type T. func MaxUint[T constraints.Unsigned]() T { return ^T(0) } // Add returns: // 1) a + b // 2) If there is overflow, an error func Add[T constraints.Unsigned](a, b T) (T, error) { if a > MaxUint[T]()-b { return 0, ErrOverflow } return a + b, nil } // Sub returns: // 1) a - b // 2) If there is underflow, an error func Sub[T constraints.Unsigned](a, b T) (T, error) { if a < b { return 0, ErrUnderflow } return a - b, nil } // Mul returns: // 1) a * b // 2) If there is overflow, an error func Mul[T constraints.Unsigned](a, b T) (T, error) { if b != 0 && a > MaxUint[T]()/b { return 0, ErrOverflow } return a * b, nil } // AbsDiff returns the absolute difference between a and b. func AbsDiff[T constraints.Unsigned](a, b T) T { return max(a, b) - min(a, b) } // SafeAdd returns x+y and whether overflow occurred. func SafeAdd(x, y uint64) (uint64, bool) { sum := x + y return sum, sum < x } // SafeSub returns x-y and whether underflow occurred. func SafeSub(x, y uint64) (uint64, bool) { return x - y, x < y } // SafeMul returns x*y and whether overflow occurred. func SafeMul(x, y uint64) (uint64, bool) { if x == 0 || y == 0 { return 0, false } result := x * y return result, result/y != x }