Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
17ead83
Add core statistical math functions
tiehuis Mar 17, 2021
cde04da
math/prob: Rename files with more descriptive english names
tiehuis Apr 2, 2021
8ba90c0
Rename bessel functions j* to besselj*
tiehuis Apr 2, 2021
4c8386e
Rename lgam to lnGamma
tiehuis Apr 2, 2021
5f8b67f
Rename ndtr to normalDist and ndtri to inverseNormalDist
tiehuis Apr 2, 2021
07c8d62
Rename incbet to incompleteBeta and incbi to inverseIncompleteBeta
tiehuis Apr 2, 2021
4b8a876
Rename incomplete gamma functions
tiehuis Apr 2, 2021
c9f1478
Update math/prob documentation
tiehuis Apr 2, 2021
3f6de49
Return result for airy fn instead of taking pointers to modify
tiehuis Apr 5, 2021
c3f8b16
Update doc comment
tiehuis Apr 5, 2021
dcfcfac
A few TODOs, and added notes on constants
EnronEvolved Aug 20, 2025
34c1b6a
Updated for loops in stdlib polevl.zig to new syntax, updated inverse…
EnronEvolved Aug 20, 2025
e8e10ac
Notes and minor style tweaks in math/prob/normal_dist.zig
EnronEvolved Aug 20, 2025
abc622d
nixed usingnamespace
EnronEvolved Aug 20, 2025
c4e56cb
fixed illegal bytes in comments, updated builtin names, and patched u…
EnronEvolved Aug 20, 2025
8a6e773
fixed unused captures and more undefinitions from nizing usingnamespace
EnronEvolved Aug 20, 2025
3fbe10a
fix moar
EnronEvolved Aug 20, 2025
d56f435
fix MOAR
EnronEvolved Aug 20, 2025
5d4e63b
constgate fixes, and two usingnamespace undef fixes
EnronEvolved Aug 20, 2025
490a3a7
constgate 2: const gater
EnronEvolved Aug 20, 2025
93261a2
Initial fixes to build tests
EnronEvolved Aug 20, 2025
f28756c
Final changes to get build success and tests passing
EnronEvolved Aug 21, 2025
2827068
Lifted constants defined in std/math/prob to std/math.zig
EnronEvolved Aug 21, 2025
32e4fda
Constant lifting, phase 2
EnronEvolved Aug 21, 2025
9b46279
Finished lifting constants
EnronEvolved Aug 21, 2025
c113149
Switched out most float-related constants for calls to comptime zig f…
EnronEvolved Aug 21, 2025
4339df0
Clarified comments in prob/constants.zig, migrated constants with wel…
EnronEvolved Aug 21, 2025
5fb81a3
Clarified airy function code, mostly with comments, but also by renam…
EnronEvolved Aug 21, 2025
d2275c4
migrate moar
EnronEvolved Aug 21, 2025
c2b125d
airy.zig: documented whatever the hell those are.
EnronEvolved Aug 23, 2025
aa7ca40
once-over with zig fmt
EnronEvolved Aug 25, 2025
882516e
Corrected inverseNormalDist as suggested by @PauloCampana
EnronEvolved Aug 27, 2025
3f7d6ec
nixed SPDX-License-Identifier in std/math/prob.zig
EnronEvolved Aug 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 42 additions & 3 deletions lib/std/math.zig
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,19 @@ pub const phi = 1.6180339887498948482045868343656381177203091798057628621;
/// Circle constant (τ)
pub const tau = 2 * pi;

/// π/4
pub const pi_4 = 0.785398163397448309616; // Cephes lift; expand

/// π/2
pub const pi_2 = 1.57079632679489661923; // Cephes lift; expand

/// 2/π
pub const two_pi = 0.636619772367581343075535; // Cephes lift; expand
// This won't get confusing at all, I swear!

/// 3π/4
pub const threepi_4 = 2.35619449019234492885; // Cephes lift; expand

/// log2(e)
pub const log2e = 1.442695040888963407359924681001892137;

Expand All @@ -27,18 +40,42 @@ pub const log10e = 0.434294481903251827651128918916605082;
/// ln(2)
pub const ln2 = 0.693147180559945309417232121458176568;

/// ln(2)/2
pub const lnsqrt2 = 0.346573590279972654709; // Cephes lift; expand

/// ln(10)
pub const ln10 = 2.302585092994045684017991454684364208;

/// ln(π)
pub const lnpi = 1.14472988584940017414; // Cephes lift; expand

/// ln(sqrt(τ))
pub const lnsqrttau = 0.91893853320467274178; // Cephes lift; expand

/// sqrt(τ)
pub const sqrttau = 2.50662827463100050242; // Cephes lift; expand

/// 2/sqrt(π)
pub const two_sqrtpi = 1.128379167095512573896158903121545172;

/// sqrt(2/π)
pub const sqrt2_pi = 0.79788456080286535587989; // Cephes lift; expand

/// sqrt(1/π)
pub const sqrt1_pi = 0.564189583547756286948; // Cephes lift; expand

/// sqrt(2)
pub const sqrt2 = 1.414213562373095048801688724209698079;

/// 1/sqrt(2)
pub const sqrt1_2 = 0.707106781186547524400844362104849039;

/// sqrt(3)
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.


/// pi/180.0
pub const rad_per_deg = 0.0174532925199432957692369076848861271344287188854172545609719144;

Expand Down Expand Up @@ -279,18 +316,18 @@ test radiansToDegrees {
const half_pi: f32 = pi / 2.0;
const neg_quart_pi: f32 = -pi / 4.0;
const one_pi: f32 = pi;
const two_pi: f32 = 2.0 * pi;
const _two_pi: f32 = 2.0 * pi;
try std.testing.expectApproxEqAbs(@as(f32, 0), radiansToDegrees(zero), 1e-6);
try std.testing.expectApproxEqAbs(@as(f32, 90), radiansToDegrees(half_pi), 1e-6);
try std.testing.expectApproxEqAbs(@as(f32, -45), radiansToDegrees(neg_quart_pi), 1e-6);
try std.testing.expectApproxEqAbs(@as(f32, 180), radiansToDegrees(one_pi), 1e-6);
try std.testing.expectApproxEqAbs(@as(f32, 360), radiansToDegrees(two_pi), 1e-6);
try std.testing.expectApproxEqAbs(@as(f32, 360), radiansToDegrees(_two_pi), 1e-6);

const result = radiansToDegrees(@Vector(4, f32){
half_pi,
neg_quart_pi,
one_pi,
two_pi,
_two_pi,
});
try std.testing.expectApproxEqAbs(@as(f32, 90), result[0], 1e-6);
try std.testing.expectApproxEqAbs(@as(f32, -45), result[1], 1e-6);
Expand Down Expand Up @@ -344,6 +381,8 @@ pub inline fn exp2(value: anytype) @TypeOf(value) {
pub const complex = @import("math/complex.zig");
pub const Complex = complex.Complex;

pub const prob = @import("math/prob.zig");

pub const big = @import("math/big.zig");

test {
Expand Down
47 changes: 47 additions & 0 deletions lib/std/math/prob.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) 2015-2021 Zig Contributors
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
// The MIT license requires this copyright notice to be included in all copies
// and substantial portions of the software.
const std = @import("std");
const testing = std.testing;
const math = std.math;

pub const normalDist = @import("prob/normal_dist.zig").normalDist;
pub const inverseNormalDist = @import("prob/normal_dist.zig").inverseNormalDist;
pub const erfc = @import("prob/normal_dist.zig").erfc;
pub const erf = @import("prob/normal_dist.zig").erf;

pub const besselj0 = @import("prob/besselj0.zig").besselj0;
pub const bessely0 = @import("prob/besselj0.zig").bessely0;
pub const besselj1 = @import("prob/besselj1.zig").besselj1;
pub const bessely1 = @import("prob/besselj1.zig").bessely1;
pub const besselj = @import("prob/besseljn.zig").besselj;

pub const airy = @import("prob/airy.zig").airy;

pub const incompleteGamma = @import("prob/incomplete_gamma.zig").incompleteGamma;
pub const complementedIncompleteGamma = @import("prob/incomplete_gamma.zig").complementedIncompleteGamma;
pub const inverseComplementedIncompleteGamma = @import("prob/incomplete_gamma.zig").inverseComplementedIncompleteGamma;

pub const gamma = @import("prob/gamma.zig").gamma;
pub const lnGamma = @import("prob/gamma.zig").lnGamma;

pub const incompleteBeta = @import("prob/incomplete_beta.zig").incompleteBeta;
pub const inverseIncompleteBeta = @import("prob/incomplete_beta.zig").inverseIncompleteBeta;

pub const polevl = @import("prob/polevl.zig").polevl;
pub const p1evl = @import("prob/polevl.zig").p1evl;

test "math.prob" {
_ = @import("prob/expx2.zig");
_ = @import("prob/polevl.zig");

_ = @import("prob/airy.zig");
_ = @import("prob/gamma.zig");
_ = @import("prob/incomplete_gamma.zig");
_ = @import("prob/incomplete_beta.zig");
_ = @import("prob/besselj0.zig");
_ = @import("prob/besselj1.zig");
_ = @import("prob/besseljn.zig");
_ = @import("prob/normal_dist.zig");
}
Loading