1use crate::compat::ToString;
4use crate::interpreter::Interpreter;
5use crate::value::{RuntimeError, Value};
6use num_bigint::BigInt;
7#[cfg(feature = "complex_numbers")]
8use num_complex::Complex64;
9use num_rational::BigRational;
10#[cfg(feature = "complex_numbers")]
11use num_traits::ToPrimitive;
12
13#[cfg(target_os = "none")]
14use num_traits::Float;
15
16pub fn mul_builtin(interp: &mut Interpreter) -> Result<(), RuntimeError> {
20 let b = interp.pop()?;
21 let a = interp.pop()?;
22
23 match (&a, &b) {
24 (Value::Int32(i1), Value::Int32(i2)) => {
29 match i1.checked_mul(*i2) {
30 Some(result) => interp.push(Value::Int32(result)),
31 None => interp.push(Value::Integer(BigInt::from(*i1) * BigInt::from(*i2))),
33 }
34 }
35
36 (Value::Number(n1), Value::Number(n2)) => {
38 interp.push(Value::Number(n1 * n2));
39 }
40
41 (Value::Integer(i1), Value::Integer(i2)) => {
43 interp.push(Value::Integer(i1 * i2));
44 }
45
46 (Value::Rational(r1), Value::Rational(r2)) => {
48 let result = Value::Rational(r1 * r2);
49 interp.push(result.demote());
50 }
51
52 #[cfg(feature = "complex_numbers")]
54 (Value::Complex(c1), Value::Complex(c2)) => {
55 interp.push(Value::Complex(c1 * c2));
56 }
57
58 #[cfg(feature = "complex_numbers")]
60 (Value::GaussianInt(a_re, a_im), Value::GaussianInt(b_re, b_im)) => {
61 let ac = a_re * b_re;
62 let bd = a_im * b_im;
63 let ad = a_re * b_im;
64 let bc = a_im * b_re;
65 let result = Value::GaussianInt(&ac - &bd, ad + bc);
66 interp.push(result.demote());
67 }
68
69 (Value::Int32(i32_val), Value::Integer(i)) | (Value::Integer(i), Value::Int32(i32_val)) => {
73 interp.push(Value::Integer(BigInt::from(*i32_val) * i));
74 }
75
76 (Value::Int32(i32_val), Value::Rational(r)) | (Value::Rational(r), Value::Int32(i32_val)) => {
78 let i_rat = BigRational::from(BigInt::from(*i32_val));
79 let result = Value::Rational(i_rat * r);
80 interp.push(result.demote());
81 }
82
83 (Value::Int32(i32_val), Value::Number(n)) | (Value::Number(n), Value::Int32(i32_val)) => {
85 interp.push(Value::Number(*i32_val as f64 * n));
86 }
87
88 #[cfg(feature = "complex_numbers")]
90 (Value::Int32(i32_val), Value::Complex(c)) | (Value::Complex(c), Value::Int32(i32_val)) => {
91 interp.push(Value::Complex(Complex64::new(*i32_val as f64, 0.0) * c));
92 }
93
94 #[cfg(feature = "complex_numbers")]
96 (Value::Int32(i32_val), Value::GaussianInt(re, im))
97 | (Value::GaussianInt(re, im), Value::Int32(i32_val)) => {
98 let result = Value::GaussianInt(re * BigInt::from(*i32_val), im * BigInt::from(*i32_val));
99 interp.push(result.demote());
100 }
101
102 (Value::Number(n), Value::Integer(i)) | (Value::Integer(i), Value::Number(n)) => {
104 if n.fract() == 0.0 && n.is_finite() {
105 let n_int = BigInt::from(*n as i64);
106 interp.push(Value::Integer(&n_int * i));
107 } else {
108 let r = float_to_rational(*n);
109 let i_rat = BigRational::from(i.clone());
110 interp.push(Value::Rational(r * i_rat));
111 }
112 }
113
114 (Value::Number(n), Value::Rational(r)) | (Value::Rational(r), Value::Number(n)) => {
116 let n_rat = float_to_rational(*n);
117 interp.push(Value::Rational(n_rat * r));
118 }
119
120 #[cfg(feature = "complex_numbers")]
122 (Value::Number(n), Value::Complex(c)) | (Value::Complex(c), Value::Number(n)) => {
123 interp.push(Value::Complex(Complex64::new(*n, 0.0) * c));
124 }
125
126 (Value::Integer(i), Value::Rational(r)) | (Value::Rational(r), Value::Integer(i)) => {
128 let i_rat = BigRational::from(i.clone());
129 let result = Value::Rational(i_rat * r);
130 interp.push(result.demote());
131 }
132
133 #[cfg(feature = "complex_numbers")]
135 (Value::Integer(i), Value::Complex(c)) | (Value::Complex(c), Value::Integer(i)) => {
136 let i_float = i.to_f64().unwrap_or(f64::INFINITY);
137 interp.push(Value::Complex(Complex64::new(i_float, 0.0) * c));
138 }
139
140 #[cfg(feature = "complex_numbers")]
142 (Value::Rational(r), Value::Complex(c)) | (Value::Complex(c), Value::Rational(r)) => {
143 let r_float = rational_to_float(r);
144 interp.push(Value::Complex(Complex64::new(r_float, 0.0) * c));
145 }
146
147 #[cfg(feature = "complex_numbers")]
149 (Value::GaussianInt(re, im), Value::Integer(i))
150 | (Value::Integer(i), Value::GaussianInt(re, im)) => {
151 let result = Value::GaussianInt(re * i, im * i);
152 interp.push(result.demote());
153 }
154
155 #[cfg(feature = "complex_numbers")]
157 (Value::GaussianInt(re, im), Value::Number(n))
158 | (Value::Number(n), Value::GaussianInt(re, im)) => {
159 let re_float = re.to_f64().unwrap_or(f64::INFINITY);
160 let im_float = im.to_f64().unwrap_or(f64::INFINITY);
161 interp.push(Value::Complex(
162 Complex64::new(re_float, im_float) * Complex64::new(*n, 0.0),
163 ));
164 }
165
166 #[cfg(feature = "complex_numbers")]
168 (Value::GaussianInt(re, im), Value::Rational(r))
169 | (Value::Rational(r), Value::GaussianInt(re, im)) => {
170 let re_float = re.to_f64().unwrap_or(f64::INFINITY);
171 let im_float = im.to_f64().unwrap_or(f64::INFINITY);
172 let r_float = rational_to_float(r);
173 interp.push(Value::Complex(
174 Complex64::new(re_float, im_float) * Complex64::new(r_float, 0.0),
175 ));
176 }
177
178 #[cfg(feature = "complex_numbers")]
180 (Value::GaussianInt(re, im), Value::Complex(c))
181 | (Value::Complex(c), Value::GaussianInt(re, im)) => {
182 let re_float = re.to_f64().unwrap_or(f64::INFINITY);
183 let im_float = im.to_f64().unwrap_or(f64::INFINITY);
184 interp.push(Value::Complex(Complex64::new(re_float, im_float) * c));
185 }
186
187 _ => {
188 return Err(RuntimeError::TypeError(
189 "Multiplication requires numbers".to_string(),
190 ));
191 }
192 }
193
194 Ok(())
195}
196
197fn float_to_rational(f: f64) -> BigRational {
199 use num_bigint::ToBigInt;
200 use num_traits::Zero;
201
202 if !f.is_finite() {
203 return BigRational::zero();
204 }
205
206 let denominator = 1_000_000_000i64;
207 let numerator = (f * denominator as f64).round() as i64;
208
209 BigRational::new(
210 numerator.to_bigint().unwrap(),
211 denominator.to_bigint().unwrap(),
212 )
213}
214
215#[cfg(feature = "complex_numbers")]
217fn rational_to_float(r: &BigRational) -> f64 {
218 let numer = r.numer().to_f64().unwrap_or(0.0);
219 let denom = r.denom().to_f64().unwrap_or(1.0);
220 numer / denom
221}
222
223#[cfg(test)]
224mod tests {
225 use super::*;
226 use crate::value::Value;
227
228 fn setup_interpreter() -> Interpreter {
229 Interpreter::new()
230 }
231
232 #[test]
233 fn test_mul_builtin() {
234 let mut interp = setup_interpreter();
235
236 interp.push(Value::Number(4.0));
238 interp.push(Value::Number(3.0));
239 mul_builtin(&mut interp).unwrap();
240
241 let result = interp.pop().unwrap();
242 assert!(matches!(result, Value::Number(n) if n == 12.0));
243
244 interp.push(Value::Number(-2.0));
246 interp.push(Value::Number(7.0));
247 mul_builtin(&mut interp).unwrap();
248
249 let result = interp.pop().unwrap();
250 assert!(matches!(result, Value::Number(n) if n == -14.0));
251
252 interp.push(Value::Number(42.0));
254 interp.push(Value::Number(0.0));
255 mul_builtin(&mut interp).unwrap();
256
257 let result = interp.pop().unwrap();
258 assert!(matches!(result, Value::Number(n) if n == 0.0));
259
260 interp.push(Value::Number(2.5));
262 interp.push(Value::Number(4.0));
263 mul_builtin(&mut interp).unwrap();
264
265 let result = interp.pop().unwrap();
266 assert!(matches!(result, Value::Number(n) if n == 10.0));
267 }
268
269 #[test]
270 fn test_mul_builtin_stack_underflow() {
271 let mut interp = setup_interpreter();
272
273 let result = mul_builtin(&mut interp);
275 assert!(matches!(result, Err(RuntimeError::StackUnderflow)));
276
277 interp.push(Value::Number(5.0));
279 let result = mul_builtin(&mut interp);
280 assert!(matches!(result, Err(RuntimeError::StackUnderflow)));
281 }
282
283 #[test]
284 fn test_mul_builtin_type_error() {
285 let mut interp = setup_interpreter();
286
287 let atom = interp.intern_atom("not-a-number");
289 interp.push(Value::Atom(atom));
290 interp.push(Value::Number(5.0));
291 let result = mul_builtin(&mut interp);
292 assert!(matches!(result, Err(RuntimeError::TypeError(_))));
293 }
294
295 #[test]
296 #[cfg(feature = "complex_numbers")]
297 fn test_mul_gaussian_int() {
298 let mut interp = setup_interpreter();
299
300 interp.push(Value::GaussianInt(BigInt::from(0), BigInt::from(1))); interp.push(Value::GaussianInt(BigInt::from(0), BigInt::from(1))); mul_builtin(&mut interp).unwrap();
304
305 let result = interp.pop().unwrap();
306 assert!(matches!(result, Value::Int32(-1)));
307
308 interp.push(Value::GaussianInt(BigInt::from(3), BigInt::from(4)));
310 interp.push(Value::GaussianInt(BigInt::from(2), BigInt::from(1)));
311 mul_builtin(&mut interp).unwrap();
312
313 let result = interp.pop().unwrap();
314 assert!(matches!(
315 result,
316 Value::GaussianInt(ref re, ref im)
317 if re == &BigInt::from(2) && im == &BigInt::from(11)
318 ));
319 }
320
321 #[test]
322 #[cfg(feature = "complex_numbers")]
323 fn test_mul_gaussian_int_with_integer() {
324 let mut interp = setup_interpreter();
325
326 interp.push(Value::GaussianInt(BigInt::from(3), BigInt::from(4)));
328 interp.push(Value::Integer(BigInt::from(5)));
329 mul_builtin(&mut interp).unwrap();
330
331 let result = interp.pop().unwrap();
332 assert!(matches!(
333 result,
334 Value::GaussianInt(ref re, ref im)
335 if re == &BigInt::from(15) && im == &BigInt::from(20)
336 ));
337 }
338}