golang/go

proposal: go/math: add generic numeric utilities

Closed this issue · 5 comments

Proposal Details

Abstract

This proposal suggests extending the existing math package to include generic versions of core mathematical functions such as Abs, Pow, Log, and Sin, leveraging Go’s type parameters (generics) introduced in Go 1.18.

The goal is to make the math package more expressive and reusable for different numeric types while maintaining full backward compatibility with existing float64-specific APIs.


Background

Currently, the math package only supports float64 operations. While this design has served well historically, it limits flexibility for developers working with other numeric types such as float32, int, or complex.

For example, if a developer needs to compute an absolute value or a power function for integers, they must either:

  • convert values to float64, risking precision loss, or
  • reimplement basic logic (e.g., if x < 0 { return -x }).

With the advent of generics and the availability of the constraints package, it’s now possible to define type-safe, efficient, and reusable versions of mathematical functions that work across numeric types without reflection or unsafe casting.


Proposal

Extend the existing math package by introducing generic equivalents for certain mathematical functions, while keeping the existing ones intact for backward compatibility.

For example:

package math

import "golang.org/x/exp/constraints"

// Abs returns the absolute value of x.
func Abs[T constraints.Signed | constraints.Float](x T) T {
    if x < 0 {
        return -x
    }
    return x
}

// Pow returns x raised to the power y.
func Pow[T constraints.Float](x, y T) T {
    // Generic version can delegate to existing math.Pow for float64
    // or provide type-specific behavior for float32.
    return T(math.Pow(float64(x), float64(y)))
}

// Log returns the natural logarithm of x.
func Log[T constraints.Float](x T) T {
    return T(math.Log(float64(x)))
}

// Sin returns the sine of the radian argument x.
func Sin[T constraints.Float](x T) T {
    return T(math.Sin(float64(x)))
}

These functions already exist in the math package. We can't change them to be generic. They have to have different names, or be in a different package.

Separately, people who are intentionally using float32 rather than float64 may be doing that for efficiency. Computing these functions with float64 precision is likely to be less efficient than computing them with float32 precision. It's not obvious that there is a good way to write generic versions of these functions that are satisfactory for all callers.

Thank you for the clarification — that makes perfect sense.

To address the compatibility and performance concerns, I would like to propose creating a new experimental package named generic-math, separate from the existing math package.

This package could provide generic versions of common mathematical functions (e.g., Abs, Pow, Log, Sin, etc.) implemented using Go's type parameters, while keeping the current math APIs unchanged. It would serve as a safe environment to explore and benchmark generic math patterns without impacting existing users.

I’m happy to start working on an initial draft implementation for this package and open a design discussion or prototype PR if the idea sounds reasonable to the Go team.

That's a fine idea but there's no reason it has to be in the standard library.

Thank you, Ian — that makes sense.

I can start developing this as an external module (e.g., github.com/mostafakhairy/generic-math) to experiment with the API design, performance benchmarks, and type constraints for generic math functions such as Abs, Pow, Log, and Sin.

Would it be appropriate, once the package matures and gains some adoption, to propose moving it under golang.org/x/exp for broader community feedback and potential inclusion in the extended Go ecosystem?

Yes, that would be appropriate if there is interest.

Closing out this issue. Thanks.