rust-lang / libs-team

The home of the library team
Apache License 2.0
127 stars 19 forks source link

Add error functions (`erf`, `erfc`) to the `f32`/`f64` API. #352

Open avhz opened 8 months ago

avhz commented 8 months ago

Proposal

Problem statement

The f32/f64 APIs are missing some useful functions, namely erf and erfc, such as in libm (where the current gamma function is from I believe) or the C++ Faddeeva library.

Motivating examples or use cases

The error function is used in numerous areas of scientific computing, such as statistics where the CDF of the Normal Distribution can be written in terms of it:

$$ \mathbb{P}(X \leq x) = F_X(x) = \Phi\left(\frac{x-\mu}{\sigma}\right) = \frac{1}{2} \left[ 1 + \text{erf}\left( \frac{x-\mu}{\sigma\sqrt{2}} \right) \right] $$

Solution sketch

As far as I can tell, the float functions are already from the libm crate, and erf, erfc have just been skipped for some reason.

Alternatives

There are obviously multiple ways to implement integrals numerically, but if the gamma function from libm was good enough, I don't see why the error function wouldn't be.

Another alternative is to port the Faddeeva library from C++ (released under an MIT licence).

Links and related work

kennytm commented 8 months ago

IMO the only reason to add erf and erfc is matching the content of math.h in C99 / C++11. The implementation should just defer to the build environment's libm.a or compiler-builtins i.e.

extern "C" {
    fn erf(x: f64) -> f64;
}
...
impl f64 {
    pub fn erf(self) -> Self {
        unsafe { cmath::erf(self) }
    }
}

POSIX also defined the Bessel functions (j0, j1, jn, y0, y1, yn), but these are not part of any C standard. That being said lgamma_r referred in cmath.rs is also not part of C99 either, not even POSIX.

The gamma functions (rust-lang/rust#99842) are still not stable yet. But rust-lang/rust#26350 explicitly mentioned tgamma as something that should not be part of standard library. Certainly the same argument applies to erf.

LachaC commented 8 months ago

package-lock.json

avhz commented 8 months ago

package-lock.json

What is this? Is it relevant?

avhz commented 8 months ago

@kennytm all valid points. Is there anyone else worth checking with? I can close the issue if not.

m-ou-se commented 7 months ago

Cc @workingjubilee, since you usually have useful opinions on floating point stuff. :)

pezcore commented 7 months ago

Can someone offer a clarifying explanation of why f32::erf, f64::erf, f32::erfc, and f64::erfc should not be added to std? It appears that on Rust 1.77, std provides methods for logarithms, cube root, trig functions, and Gamma functions on floating point primatives. Is there a reason why these functions should be provided by std but erf and erfc should not? What is different about erf and erfc relative to these functions that justifies their exclusion from std?

I admit that I agree that std should probably not provide methods for every single named function of the Reals, as doing so could cause users to face low SNR in the documentation and could pose unwanted maintenance burden for the maintainers, but the line drawn as it currently is seems pretty arbitrary to me.

kennytm commented 7 months ago

@pezcore

Elementary functions like log and sin/cos can be lowered to LLVM intrinsics so the core library can stay not explicitly relying on libm thus avoiding rust-lang/rust#26350.

gamma is not yet stable, and could be removed because of the libm dependency (see my comment above https://github.com/rust-lang/libs-team/issues/352#issuecomment-1992094858).

IMO if we accept (stabilize) gamma we should also accept erf, and if we remove gamma there is no reason for erf in std either.