Skip to content

Conversation

EnronEvolved
Copy link

@EnronEvolved EnronEvolved commented Aug 23, 2025

This is a resurrection of #8313, with a view to closing #7212. Proposed (and sometimes partially complete) changes on top of @tiehuis's work include:

  • Reuse of pre-existing constants from std/math.zig, such as pi, sqrt1_2, and machine epsilons.
  • Lifting of new constants from individual files under std/math/prob to std/math.zig.
    • std/math/prob/constants.zig still exists until the lifted constants, and MINLOG and MAXLOG, have found permanent homes.
  • Reuse of pre-existing functions from std/math.zig where available, particularly gamma and lgamma.
  • Generalisation of mathematical functions to accept types other than f64.
  • Modification of besseljn.zig to accept rational numbers directly, in addition to floating point numbers.

I have a few questions about how to proceed:

  • What are the established practices for new constants in std.math? A lot of the proposed additions are rational multiples of pre-existing constants. math.zig seems a bit inconsistent with how it handles these cases; tau is defined as 2.0 * pi but sqrt2 and sqrt1_2 are defined independently.
  • How precise do constants need to be? The additions from Cephes are noticeably less precise than the pre-existing constants.
  • Should these new functions remain under prob (or a similarly-named folder), to keep the 3rd-party MIT-licenced code separate, or be moved to directly under math like the musl code? There really isn't a conceptual case for a folder called prob: there's code in there unrelated to statistics, like a function for evaluating polynomials given coefficients.
  • In order to generalise some of the functions, the natural logarithms of floatMax and floatMin values will be necessary. Should these be precalculated results or whatever ln(floatMin/Max(…)) produces?

Answers to these questions, responses to these proposals, and any other input or feedback, are very much welcome.

tiehuis and others added 30 commits August 20, 2025 11:36
The key functions added are:

    // Regularized incomplete beta function
    pub fn incbet(a: f64, b: f64, x: f64) f64

    // Inverse of incomplete beta integral
    pub fn incbi(a: f64, b: f64, y: f64) f64

    // Regularized incomplete gamma integral
    pub fn igam(a: f64, x: f64) f64

    // Complemented incomplete gamma integral
    pub fn igamc(a: f64, x: f64) f64

    // Inverse of complemented incomplete gamma integral
    pub fn igami(a: f64, p: f64) f64

    // Normal distribution function
    pub fn ndtr(x: f64) f64

    // Inverse of Normal distribution function
    pub fn ndtri(y: f64) f64

    // Bessel function of non-integer order
    pub fn jv(v: f64, x: f64) f64

Some extra functions besides these have been exposed as well, largely
functions which the above are dependent on, but which may have relevant
use outside.

Tests are largely generated from external sources and verified, since
cephes, the library which these implementations has been ported from
lacks formal testcases.

Closes ziglang#7212.
Limited what we export and merged some inverse functions into general
files.
Remove DEC accuracy references, we don't support DEC.

Rename function references in comments to either the name of the
function, or a generic one if it can easily be inferred from context.

Don't use expx2 function by default. Want to confirm how required this
is and remove if it isn't considered too necessary for the accuracy.
… incomplete beta to use a labelled switch, more constant notes
…ndefined constants from usingnamespace removal
…l-established names in functions to point to math.zig directly.
@EnronEvolved EnronEvolved changed the title Adding the "elusive eight" special functions to std.math std: Adding the "elusive eight" special functions to std.math Aug 23, 2025
@EnronEvolved EnronEvolved changed the title std: Adding the "elusive eight" special functions to std.math std: add the "elusive eight" special functions to std.math Aug 25, 2025
@EnronEvolved
Copy link
Author

I've ran zig fmt --check locally after pushing the latest commit, and it seems to pass. That was where the tests were failing before, so hopefully they pass the next time around.

pub const sqrt3 = 1.732050807568877293527; // Cephes lift; expand

/// cbrt(2)
pub const cbrt2 = std.math.cbrt(@as(f64, 2.0)); // Cephes lift; expand
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume the multiple "Cephes lift; expand" means that the constants should be recalculated to have at least 128 bit floating point precision? (113 bits of mantissa) - If so, here ya go :)

pub const e = 2.718281828459045235360287471352662498;
pub const pi = 3.141592653589793238462643383279502884;
pub const phi = 1.618033988749894848204586834365638118;
pub const tau = 6.283185307179586476925286766559005768;
pub const pi_4 = 0.785398163397448309615660845819875721;
pub const pi_2 = 1.570796326794896619231321691639751442;
pub const two_pi = 0.636619772367581343075535053490057448; // yeah, the name is a bit confusing. Perhaps inv_pi_2 would fit better?
pub const threepi_4 = 2.356194490192344928846982537459627163;
pub const log2e = 1.442695040888963407359924681001892137;
pub const ln2 = 0.693147180559945309417232121458176568;
pub const lnsqrt2 = 0.346573590279972654708616060729088284;
pub const ln10 = 2.302585092994045684017991454684364208;
pub const lnpi = 1.144729885849400174143427351353058712;
pub const lnsqrttau = 0.918938533204672741780329736405617640;
pub const sqrttau = 2.506628274631000502415765284811045253;
pub const two_sqrtpi = 1.128379167095512573896158903121545172;
pub const sqrt2_pi = 0.797884560802865355879892119868763737;
pub const sqrt1_pi = 0.564189583547756286948079451560772586;
pub const sqrt2 = 1.414213562373095048801688724209698079;
pub const sqrt1_2 = 0.707106781186547524400844362104849039;
pub const sqrt3 = 1.732050807568877293527446341505872367;
pub const cbrt2 = 1.259921049894873164767210607278228351;
pub const rad_per_deg = 0.0174532925199432957692369076848861271344;
pub const deg_per_rad = 57.295779513082320876798154814105170332405;

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of these constants (pi, e, phi, rad_per_deg deg_per_rad) are actually less precise than the ones already in std/math.zig.

There doesn't appear to be any documented rationale for the precision of floating point constants. Most of them are sufficient for quadruple precision, but some (namely the aforementioned) exceed quadruple precision but remain insufficient for octuple precision.

I guess this is another reason for why I was asking about best practices.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK comptime_float is just an f128, so these all match the required precision. Of course, I'd be happy to calculate them to a higher precision.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants