cas_compute/funcs/
miscellaneous.rs1use cas_attrs::builtin;
4use crate::consts::TAU;
5use crate::numerical::value::Value;
6use crate::primitive::{complex, float_from_str, float, int};
7use once_cell::sync::Lazy;
8use rand::Rng;
9use rug::{integer::Order, ops::Pow, rand::RandState, Complex, Float, Integer};
10
11#[derive(Debug)]
13pub struct Abs;
14
15#[cfg_attr(feature = "numerical", builtin)]
16impl Abs {
17 pub fn eval_static(v: Complex) -> Float {
18 v.abs().into_real_imag().0
19 }
20}
21
22#[derive(Debug)]
34pub struct Bool;
35
36#[cfg_attr(feature = "numerical", builtin)]
37impl Bool {
38 pub fn eval_static(v: Value) -> bool {
39 v.is_truthy()
40 }
41}
42
43#[derive(Debug)]
45pub struct Rand;
46
47#[cfg_attr(feature = "numerical", builtin)]
48impl Rand {
49 pub fn eval_static() -> Float {
50 let mut seed = Integer::new();
51 let mut digits = [0u128; 2]; rand::thread_rng().fill(&mut digits);
53 seed.assign_digits(&digits, Order::Lsf);
54
55 let mut rand_state = RandState::new();
56 rand_state.seed(&seed);
57 float(Float::random_bits(&mut rand_state))
58 }
59}
60
61pub fn partial_factorial(mut n: Integer, k: Integer) -> Integer {
64 let mut result = int(1);
65 while n > k {
66 result *= &n;
67 n -= 1;
68 }
69 result
70}
71
72#[derive(Debug)]
74pub struct Factorial;
75
76#[cfg_attr(feature = "numerical", builtin)]
77impl Factorial {
78 pub fn eval_static(n: Float) -> Value {
79 if !n.is_integer() || n.is_sign_negative() {
80 Value::Float((n + 1u8).gamma())
81 } else {
82 let n_int = n.to_integer().unwrap();
83
84 if let Some(n) = n_int.to_u16() {
87 Value::Integer(int(Integer::factorial(u32::from(n))))
88 } else {
89 Value::Float((n + 1u8).gamma())
92 }
93 }
94 }
95}
96
97static GAMMA_P: Lazy<[Float; 9]> = Lazy::new(|| [
98 float_from_str("0.99999999999980993"),
99 float_from_str("676.5203681218851"),
100 float_from_str("-1259.1392167224028"),
101 float_from_str("771.32342877765313"),
102 float_from_str("-176.61502916214059"),
103 float_from_str("12.507343278686905"),
104 float_from_str("-0.13857109526572012"),
105 float_from_str("9.9843695780195716e-6"),
106 float_from_str("1.5056327351493116e-7"),
107]);
108
109static GAMMA_G: Lazy<Float> = Lazy::new(|| float(7));
110
111#[derive(Debug)]
113pub struct Gamma;
114
115#[cfg_attr(feature = "numerical", builtin)]
116impl Gamma {
117 pub fn eval_static(mut z: Complex) -> Complex {
118 if z.imag().is_zero() {
120 return complex(z.into_real_imag().0.gamma());
121 }
122
123 z -= 1;
124
125 let mut x = complex(&GAMMA_P[0]);
126 for (i, p) in GAMMA_P.iter().enumerate().skip(1) {
127 x += p / complex(&z + i);
128 }
129
130 let t = complex(complex(&z + &*GAMMA_G) + 0.5);
131
132 let tau_sqrt = float(&*TAU).sqrt();
133 let t_pow = (&t).pow(z + 0.5);
134 let exp_t = complex(t.as_neg().exp_ref());
135
136 x * t_pow * exp_t * tau_sqrt
137 }
138}
139
140#[derive(Debug)]
142pub struct Lerp;
143
144#[cfg_attr(feature = "numerical", builtin)]
145impl Lerp {
146 pub fn eval_static(v1: Complex, v2: Complex, t: Float) -> Complex {
147 &v1 + (v2 - &v1) * t
148 }
149}
150
151#[derive(Debug)]
153pub struct Invlerp;
154
155#[cfg_attr(feature = "numerical", builtin)]
156impl Invlerp {
157 pub fn eval_static(v1: Float, v2: Float, v: Float) -> Float {
158 (v - &v1) / (v2 - &v1)
159 }
160}
161
162#[derive(Debug)]
164pub struct Min;
165
166#[cfg_attr(feature = "numerical", builtin)]
167impl Min {
168 pub fn eval_static(v1: Float, v2: Float) -> Float {
169 v1.min(&v2)
170 }
171}
172
173#[derive(Debug)]
175pub struct Max;
176
177#[cfg_attr(feature = "numerical", builtin)]
178impl Max {
179 pub fn eval_static(v1: Float, v2: Float) -> Float {
180 v1.max(&v2)
181 }
182}
183
184#[derive(Debug)]
186pub struct Clamp;
187
188#[cfg_attr(feature = "numerical", builtin)]
189impl Clamp {
190 pub fn eval_static(v: Float, min: Float, max: Float) -> Float {
191 v.clamp(&min, &max)
192 }
193}
194
195#[derive(Debug)]
197pub struct Gcf;
198
199#[cfg_attr(feature = "numerical", builtin)]
200impl Gcf {
201 pub fn eval_static(a: Integer, b: Integer) -> Integer {
202 a.gcd(&b)
203 }
204}
205
206#[derive(Debug)]
208pub struct Lcm;
209
210#[cfg_attr(feature = "numerical", builtin)]
211impl Lcm {
212 pub fn eval_static(a: Integer, b: Integer) -> Integer {
213 a.lcm(&b)
214 }
215}
216
217#[derive(Debug)]
219pub struct Sign;
220
221#[cfg_attr(feature = "numerical", builtin)]
222impl Sign {
223 pub fn eval_static(v: Float) -> Float {
224 if v.is_zero() {
225 v
226 } else {
227 v.signum()
228 }
229 }
230}
231
232#[derive(Debug)]
234pub struct Size;
235
236#[cfg_attr(feature = "numerical", builtin)]
237impl Size {
238 pub fn eval_static(v: Integer) -> Integer {
239 v.significant_bits().into()
240 }
241}