From 2df6cabee0067fc0214cd9e246bcb2c9521f61b8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 22 May 2023 11:59:44 +0100 Subject: [PATCH] Add `@(require_results)` to `core:math/rand` --- core/math/rand/distributions.odin | 26 ++++++++++++++++++++++++++ core/math/rand/exp.odin | 1 + core/math/rand/normal.odin | 1 + core/math/rand/rand.odin | 25 ++++++++++++++++++------- core/math/rand/system_darwin.odin | 1 + core/math/rand/system_linux.odin | 1 + core/math/rand/system_windows.odin | 1 + 7 files changed, 49 insertions(+), 7 deletions(-) diff --git a/core/math/rand/distributions.odin b/core/math/rand/distributions.odin index ada89afad..9365e8b76 100644 --- a/core/math/rand/distributions.odin +++ b/core/math/rand/distributions.odin @@ -7,6 +7,7 @@ float32_uniform :: float32_range // Triangular Distribution // See: http://wikipedia.org/wiki/Triangular_distribution +@(require_results) float64_triangular :: proc(lo, hi: f64, mode: Maybe(f64), r: ^Rand = nil) -> f64 { if hi-lo == 0 { return lo @@ -24,6 +25,7 @@ float64_triangular :: proc(lo, hi: f64, mode: Maybe(f64), r: ^Rand = nil) -> f64 } // Triangular Distribution // See: http://wikipedia.org/wiki/Triangular_distribution +@(require_results) float32_triangular :: proc(lo, hi: f32, mode: Maybe(f32), r: ^Rand = nil) -> f32 { if hi-lo == 0 { return lo @@ -41,20 +43,24 @@ float32_triangular :: proc(lo, hi: f32, mode: Maybe(f32), r: ^Rand = nil) -> f32 // Normal/Gaussian Distribution +@(require_results) float64_normal :: proc(mean, stddev: f64, r: ^Rand = nil) -> f64 { return norm_float64(r) * stddev + mean } // Normal/Gaussian Distribution +@(require_results) float32_normal :: proc(mean, stddev: f32, r: ^Rand = nil) -> f32 { return f32(float64_normal(f64(mean), f64(stddev), r)) } // Log Normal Distribution +@(require_results) float64_log_normal :: proc(mean, stddev: f64, r: ^Rand = nil) -> f64 { return math.exp(float64_normal(mean, stddev, r)) } // Log Normal Distribution +@(require_results) float32_log_normal :: proc(mean, stddev: f32, r: ^Rand = nil) -> f32 { return f32(float64_log_normal(f64(mean), f64(stddev), r)) } @@ -65,6 +71,7 @@ float32_log_normal :: proc(mean, stddev: f32, r: ^Rand = nil) -> f32 { // Return values range from // 0 to positive infinity if lambda > 0 // negative infinity to 0 if lambda <= 0 +@(require_results) float64_exponential :: proc(lambda: f64, r: ^Rand = nil) -> f64 { return - math.ln(1 - float64(r)) / lambda } @@ -73,6 +80,7 @@ float64_exponential :: proc(lambda: f64, r: ^Rand = nil) -> f64 { // Return values range from // 0 to positive infinity if lambda > 0 // negative infinity to 0 if lambda <= 0 +@(require_results) float32_exponential :: proc(lambda: f32, r: ^Rand = nil) -> f32 { return f32(float64_exponential(f64(lambda), r)) } @@ -87,6 +95,7 @@ float32_exponential :: proc(lambda: f32, r: ^Rand = nil) -> f32 { // math.gamma(alpha) * math.pow(beta, alpha) // // mean is alpha*beta, variance is math.pow(alpha*beta, 2) +@(require_results) float64_gamma :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 { if alpha <= 0 || beta <= 0 { panic(#procedure + ": alpha and beta must be > 0.0") @@ -152,6 +161,7 @@ float64_gamma :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 { // math.gamma(alpha) * math.pow(beta, alpha) // // mean is alpha*beta, variance is math.pow(alpha*beta, 2) +@(require_results) float32_gamma :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 { return f32(float64_gamma(f64(alpha), f64(beta), r)) } @@ -162,6 +172,7 @@ float32_gamma :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 { // Required: alpha > 0 and beta > 0 // // Return values range between 0 and 1 +@(require_results) float64_beta :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 { if alpha <= 0 || beta <= 0 { panic(#procedure + ": alpha and beta must be > 0.0") @@ -178,6 +189,7 @@ float64_beta :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 { // Required: alpha > 0 and beta > 0 // // Return values range between 0 and 1 +@(require_results) float32_beta :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 { return f32(float64_beta(f64(alpha), f64(beta), r)) } @@ -185,22 +197,26 @@ float32_beta :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 { // Pareto distribution, `alpha` is the shape parameter. // https://wikipedia.org/wiki/Pareto_distribution +@(require_results) float64_pareto :: proc(alpha: f64, r: ^Rand = nil) -> f64 { return math.pow(1 - float64(r), -1.0 / alpha) } // Pareto distribution, `alpha` is the shape parameter. // https://wikipedia.org/wiki/Pareto_distribution +@(require_results) float32_pareto :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 { return f32(float64_pareto(f64(alpha), r)) } // Weibull distribution, `alpha` is the scale parameter, `beta` is the shape parameter. +@(require_results) float64_weibull :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 { u := 1 - float64(r) return alpha * math.pow(-math.ln(u), 1.0/beta) } // Weibull distribution, `alpha` is the scale parameter, `beta` is the shape parameter. +@(require_results) float32_weibull :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 { return f32(float64_weibull(f64(alpha), f64(beta), r)) } @@ -210,6 +226,7 @@ float32_weibull :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 { // `mean_angle` is the in mean angle between 0 and 2pi radians // `kappa` is the concentration parameter which must be >= 0 // When `kappa` is zero, the Distribution is a uniform Distribution over the range 0 to 2pi +@(require_results) float64_von_mises :: proc(mean_angle, kappa: f64, r: ^Rand = nil) -> f64 { // Fisher, N.I., "Statistical Analysis of Circular Data", Cambridge University Press, 1993. @@ -245,6 +262,7 @@ float64_von_mises :: proc(mean_angle, kappa: f64, r: ^Rand = nil) -> f64 { // `mean_angle` is the in mean angle between 0 and 2pi radians // `kappa` is the concentration parameter which must be >= 0 // When `kappa` is zero, the Distribution is a uniform Distribution over the range 0 to 2pi +@(require_results) float32_von_mises :: proc(mean_angle, kappa: f32, r: ^Rand = nil) -> f32 { return f32(float64_von_mises(f64(mean_angle), f64(kappa), r)) } @@ -252,6 +270,7 @@ float32_von_mises :: proc(mean_angle, kappa: f32, r: ^Rand = nil) -> f32 { // Cauchy-Lorentz Distribution // `x_0` is the location, `gamma` is the scale where `gamma` > 0 +@(require_results) float64_cauchy_lorentz :: proc(x_0, gamma: f64, r: ^Rand = nil) -> f64 { assert(gamma > 0) @@ -261,6 +280,7 @@ float64_cauchy_lorentz :: proc(x_0, gamma: f64, r: ^Rand = nil) -> f64 { } // Cauchy-Lorentz Distribution // `x_0` is the location, `gamma` is the scale where `gamma` > 0 +@(require_results) float32_cauchy_lorentz :: proc(x_0, gamma: f32, r: ^Rand = nil) -> f32 { return f32(float64_cauchy_lorentz(f64(x_0), f64(gamma), r)) } @@ -268,12 +288,14 @@ float32_cauchy_lorentz :: proc(x_0, gamma: f32, r: ^Rand = nil) -> f32 { // Log Cauchy-Lorentz Distribution // `x_0` is the location, `gamma` is the scale where `gamma` > 0 +@(require_results) float64_log_cauchy_lorentz :: proc(x_0, gamma: f64, r: ^Rand = nil) -> f64 { assert(gamma > 0) return math.exp(math.tan(math.PI * (float64(r) - 0.5))*gamma + x_0) } // Log Cauchy-Lorentz Distribution // `x_0` is the location, `gamma` is the scale where `gamma` > 0 +@(require_results) float32_log_cauchy_lorentz :: proc(x_0, gamma: f32, r: ^Rand = nil) -> f32 { return f32(float64_log_cauchy_lorentz(f64(x_0), f64(gamma), r)) } @@ -281,6 +303,7 @@ float32_log_cauchy_lorentz :: proc(x_0, gamma: f32, r: ^Rand = nil) -> f32 { // Laplace Distribution // `b` is the scale where `b` > 0 +@(require_results) float64_laplace :: proc(mean, b: f64, r: ^Rand = nil) -> f64 { assert(b > 0) p := float64(r)-0.5 @@ -288,6 +311,7 @@ float64_laplace :: proc(mean, b: f64, r: ^Rand = nil) -> f64 { } // Laplace Distribution // `b` is the scale where `b` > 0 +@(require_results) float32_laplace :: proc(mean, b: f32, r: ^Rand = nil) -> f32 { return f32(float64_laplace(f64(mean), f64(b), r)) } @@ -296,6 +320,7 @@ float32_laplace :: proc(mean, b: f32, r: ^Rand = nil) -> f32 { // Gompertz Distribution // `eta` is the shape, `b` is the scale // Both `eta` and `b` must be > 0 +@(require_results) float64_gompertz :: proc(eta, b: f64, r: ^Rand = nil) -> f64 { if eta <= 0 || b <= 0 { panic(#procedure + ": eta and b must be > 0.0") @@ -307,6 +332,7 @@ float64_gompertz :: proc(eta, b: f64, r: ^Rand = nil) -> f64 { // Gompertz Distribution // `eta` is the shape, `b` is the scale // Both `eta` and `b` must be > 0 +@(require_results) float32_gompertz :: proc(eta, b: f32, r: ^Rand = nil) -> f32 { return f32(float64_gompertz(f64(eta), f64(b), r)) } diff --git a/core/math/rand/exp.odin b/core/math/rand/exp.odin index c0f92e99c..719debe75 100644 --- a/core/math/rand/exp.odin +++ b/core/math/rand/exp.odin @@ -15,6 +15,7 @@ import "core:math" // https://www.jstatsoft.org/index.php/jss/article/view/v005i08/ziggurat.pdf [pdf] // https://www.jstatsoft.org/article/view/v005i08 [web page] // +@(require_results) exp_float64 :: proc(r: ^Rand = nil) -> f64 { re :: 7.69711747013104972 diff --git a/core/math/rand/normal.odin b/core/math/rand/normal.odin index a9edd0f19..f96163fe9 100644 --- a/core/math/rand/normal.odin +++ b/core/math/rand/normal.odin @@ -17,6 +17,7 @@ import "core:math" // https://www.jstatsoft.org/index.php/jss/article/view/v005i08/ziggurat.pdf [pdf] // https://www.jstatsoft.org/article/view/v005i08 [web page] // +@(require_results) norm_float64 :: proc(r: ^Rand = nil) -> f64 { rn :: 3.442619855899 diff --git a/core/math/rand/rand.odin b/core/math/rand/rand.odin index 2d92d29ff..825aa7b87 100644 --- a/core/math/rand/rand.odin +++ b/core/math/rand/rand.odin @@ -16,6 +16,7 @@ set_global_seed :: proc(seed: u64) { init(&global_rand, seed) } +@(require_results) create :: proc(seed: u64) -> Rand { r: Rand init(&r, seed) @@ -60,14 +61,17 @@ _random :: proc(r: ^Rand) -> u32 { return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 31)) } +@(require_results) uint32 :: proc(r: ^Rand = nil) -> u32 { return _random(r) } +@(require_results) uint64 :: proc(r: ^Rand = nil) -> u64 { a := u64(_random(r)) b := u64(_random(r)) return (a<<32) | b } +@(require_results) uint128 :: proc(r: ^Rand = nil) -> u128 { a := u128(_random(r)) b := u128(_random(r)) @@ -76,10 +80,11 @@ uint128 :: proc(r: ^Rand = nil) -> u128 { return (a<<96) | (b<<64) | (c<<32) | d } -int31 :: proc(r: ^Rand = nil) -> i32 { return i32(uint32(r) << 1 >> 1) } -int63 :: proc(r: ^Rand = nil) -> i64 { return i64(uint64(r) << 1 >> 1) } -int127 :: proc(r: ^Rand = nil) -> i128 { return i128(uint128(r) << 1 >> 1) } +@(require_results) int31 :: proc(r: ^Rand = nil) -> i32 { return i32(uint32(r) << 1 >> 1) } +@(require_results) int63 :: proc(r: ^Rand = nil) -> i64 { return i64(uint64(r) << 1 >> 1) } +@(require_results) int127 :: proc(r: ^Rand = nil) -> i128 { return i128(uint128(r) << 1 >> 1) } +@(require_results) int31_max :: proc(n: i32, r: ^Rand = nil) -> i32 { if n <= 0 { panic("Invalid argument to int31_max") @@ -95,6 +100,7 @@ int31_max :: proc(n: i32, r: ^Rand = nil) -> i32 { return v % n } +@(require_results) int63_max :: proc(n: i64, r: ^Rand = nil) -> i64 { if n <= 0 { panic("Invalid argument to int63_max") @@ -110,6 +116,7 @@ int63_max :: proc(n: i64, r: ^Rand = nil) -> i64 { return v % n } +@(require_results) int127_max :: proc(n: i128, r: ^Rand = nil) -> i128 { if n <= 0 { panic("Invalid argument to int127_max") @@ -125,6 +132,7 @@ int127_max :: proc(n: i128, r: ^Rand = nil) -> i128 { return v % n } +@(require_results) int_max :: proc(n: int, r: ^Rand = nil) -> int { if n <= 0 { panic("Invalid argument to int_max") @@ -137,13 +145,14 @@ int_max :: proc(n: int, r: ^Rand = nil) -> int { } // Uniform random distribution [0, 1) -float64 :: proc(r: ^Rand = nil) -> f64 { return f64(int63_max(1<<53, r)) / (1 << 53) } +@(require_results) float64 :: proc(r: ^Rand = nil) -> f64 { return f64(int63_max(1<<53, r)) / (1 << 53) } // Uniform random distribution [0, 1) -float32 :: proc(r: ^Rand = nil) -> f32 { return f32(float64(r)) } +@(require_results) float32 :: proc(r: ^Rand = nil) -> f32 { return f32(float64(r)) } -float64_range :: proc(lo, hi: f64, r: ^Rand = nil) -> f64 { return (hi-lo)*float64(r) + lo } -float32_range :: proc(lo, hi: f32, r: ^Rand = nil) -> f32 { return (hi-lo)*float32(r) + lo } +@(require_results) float64_range :: proc(lo, hi: f64, r: ^Rand = nil) -> f64 { return (hi-lo)*float64(r) + lo } +@(require_results) float32_range :: proc(lo, hi: f32, r: ^Rand = nil) -> f32 { return (hi-lo)*float32(r) + lo } +@(require_results) read :: proc(p: []byte, r: ^Rand = nil) -> (n: int) { pos := i8(0) val := i64(0) @@ -160,6 +169,7 @@ read :: proc(p: []byte, r: ^Rand = nil) -> (n: int) { } // perm returns a slice of n ints in a pseudo-random permutation of integers in the range [0, n) +@(require_results) perm :: proc(n: int, r: ^Rand = nil, allocator := context.allocator) -> []int { m := make([]int, n, allocator) for i := 0; i < n; i += 1 { @@ -184,6 +194,7 @@ shuffle :: proc(array: $T/[]$E, r: ^Rand = nil) { } // Returns a random element from the given slice +@(require_results) choice :: proc(array: $T/[]$E, r: ^Rand = nil) -> (res: E) { n := i64(len(array)) if n < 1 { diff --git a/core/math/rand/system_darwin.odin b/core/math/rand/system_darwin.odin index f51e4473e..a2890d1b4 100644 --- a/core/math/rand/system_darwin.odin +++ b/core/math/rand/system_darwin.odin @@ -2,6 +2,7 @@ package rand import "core:sys/darwin" +@(require_results) _system_random :: proc() -> u32 { for { value: u32 diff --git a/core/math/rand/system_linux.odin b/core/math/rand/system_linux.odin index bfdc8872b..0e34228dc 100644 --- a/core/math/rand/system_linux.odin +++ b/core/math/rand/system_linux.odin @@ -2,6 +2,7 @@ package rand import "core:sys/unix" +@(require_results) _system_random :: proc() -> u32 { for { value: u32 diff --git a/core/math/rand/system_windows.odin b/core/math/rand/system_windows.odin index ee9cd0294..b6af9e6a4 100644 --- a/core/math/rand/system_windows.odin +++ b/core/math/rand/system_windows.odin @@ -2,6 +2,7 @@ package rand import win32 "core:sys/windows" +@(require_results) _system_random :: proc() -> u32 { value: u32 status := win32.BCryptGenRandom(nil, ([^]u8)(&value), 4, win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG)