mathhook_core/functions/
number_theory_eval.rs1use crate::core::constants::EPSILON;
4use crate::core::{Expression, Number};
5use num_integer::Integer;
6
7pub fn lcm(a: &Expression, b: &Expression) -> Expression {
32 match (a, b) {
33 (
34 Expression::Number(Number::Integer(a_val)),
35 Expression::Number(Number::Integer(b_val)),
36 ) => {
37 if *a_val == 0 || *b_val == 0 {
38 Expression::integer(0)
39 } else {
40 let gcd_val = a_val.gcd(b_val);
41 Expression::integer((a_val * b_val).abs() / gcd_val)
42 }
43 }
44 _ => Expression::function("lcm", vec![a.clone(), b.clone()]),
45 }
46}
47
48pub fn modulo(a: &Expression, b: &Expression) -> Expression {
73 match (a, b) {
74 (
75 Expression::Number(Number::Integer(a_val)),
76 Expression::Number(Number::Integer(b_val)),
77 ) if *b_val != 0 => Expression::integer(a_val % b_val),
78 (Expression::Number(Number::Float(a_val)), Expression::Number(Number::Float(b_val)))
79 if b_val.abs() >= EPSILON =>
80 {
81 Expression::float(a_val % b_val)
82 }
83 _ => Expression::function("mod", vec![a.clone(), b.clone()]),
84 }
85}
86
87pub fn isprime(arg: &Expression) -> Expression {
112 match arg {
113 Expression::Number(Number::Integer(n)) if *n <= 1 => Expression::integer(0),
114 Expression::Number(Number::Integer(2)) => Expression::integer(1),
115 Expression::Number(Number::Integer(n)) if n % 2 == 0 => Expression::integer(0),
116 Expression::Number(Number::Integer(n)) if *n > 0 => {
117 Expression::integer(if is_prime_trial_division(*n) { 1 } else { 0 })
118 }
119 _ => Expression::function("isprime", vec![arg.clone()]),
120 }
121}
122
123fn is_prime_trial_division(n: i64) -> bool {
124 if n <= 1 {
125 return false;
126 }
127 if n == 2 {
128 return true;
129 }
130 if n % 2 == 0 {
131 return false;
132 }
133
134 let sqrt_n = (n as f64).sqrt() as i64 + 1;
135 for i in (3..=sqrt_n).step_by(2) {
136 if n % i == 0 {
137 return false;
138 }
139 }
140 true
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146
147 #[test]
148 fn test_lcm() {
149 assert_eq!(
150 lcm(&Expression::integer(12), &Expression::integer(18)),
151 Expression::integer(36)
152 );
153 assert_eq!(
154 lcm(&Expression::integer(4), &Expression::integer(6)),
155 Expression::integer(12)
156 );
157 }
158
159 #[test]
160 fn test_modulo() {
161 assert_eq!(
162 modulo(&Expression::integer(17), &Expression::integer(5)),
163 Expression::integer(2)
164 );
165 assert_eq!(
166 modulo(&Expression::integer(10), &Expression::integer(3)),
167 Expression::integer(1)
168 );
169 }
170
171 #[test]
172 fn test_isprime() {
173 assert_eq!(isprime(&Expression::integer(2)), Expression::integer(1));
174 assert_eq!(isprime(&Expression::integer(17)), Expression::integer(1));
175 assert_eq!(isprime(&Expression::integer(19)), Expression::integer(1));
176 assert_eq!(isprime(&Expression::integer(4)), Expression::integer(0));
177 assert_eq!(isprime(&Expression::integer(9)), Expression::integer(0));
178 assert_eq!(isprime(&Expression::integer(1)), Expression::integer(0));
179 }
180}