1use crate::compat::format;
4use crate::interpreter::Interpreter;
5use crate::primitives::numeric_promotion::promote_pair;
6use crate::value::{RuntimeError, Value};
7use num_rational::BigRational;
8use num_traits::Zero;
9
10pub fn div_builtin(interp: &mut Interpreter) -> Result<(), RuntimeError> {
14 let b = interp.pop()?;
15 let a = interp.pop()?;
16
17 let is_zero = match &b {
19 Value::Int32(i) => *i == 0,
20 Value::Integer(i) => i.is_zero(),
21 Value::Rational(r) => r.is_zero(),
22 Value::Number(n) => *n == 0.0,
23 _ => false,
24 };
25 if is_zero {
26 return Err(RuntimeError::DivisionByZero);
27 }
28
29 let result = if let (Value::Int32(ia), Value::Int32(ib)) = (&a, &b) {
32 let result = Value::Rational(BigRational::new(
34 num_bigint::BigInt::from(*ia),
35 num_bigint::BigInt::from(*ib),
36 ));
37 result.demote()
38 } else if let (Value::Integer(ia), Value::Integer(ib)) = (&a, &b) {
39 let result = Value::Rational(BigRational::new(ia.clone(), ib.clone()));
40 result.demote()
41 } else {
42 let (pa, pb) = promote_pair(&a, &b);
44
45 match (&pa, &pb) {
46 (Value::Rational(r1), Value::Rational(r2)) => {
47 let result = Value::Rational(r1 / r2);
48 result.demote()
49 }
50 (Value::Number(n1), Value::Number(n2)) => Value::Number(n1 / n2),
51 #[cfg(feature = "complex_numbers")]
52 (Value::Complex(c1), Value::Complex(c2)) => Value::Complex(c1 / c2),
53 _ => {
54 return Err(RuntimeError::TypeError(format!(
55 "Cannot divide {:?} and {:?}",
56 a, b
57 )))
58 }
59 }
60 };
61
62 interp.push(result);
63 Ok(())
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69 use crate::value::Value;
70 use num_bigint::BigInt;
71 use num_rational::BigRational;
72
73 fn setup_interpreter() -> Interpreter {
74 Interpreter::new()
75 }
76
77 #[test]
78 fn test_div_builtin_floats() {
79 let mut interp = setup_interpreter();
80
81 interp.push(Value::Number(12.0));
83 interp.push(Value::Number(4.0));
84 div_builtin(&mut interp).unwrap();
85
86 let result = interp.pop().unwrap();
87 assert!(matches!(result, Value::Number(n) if n == 3.0));
88
89 interp.push(Value::Number(7.0));
91 interp.push(Value::Number(2.0));
92 div_builtin(&mut interp).unwrap();
93
94 let result = interp.pop().unwrap();
95 assert!(matches!(result, Value::Number(n) if n == 3.5));
96
97 interp.push(Value::Number(-8.0));
99 interp.push(Value::Number(2.0));
100 div_builtin(&mut interp).unwrap();
101
102 let result = interp.pop().unwrap();
103 assert!(matches!(result, Value::Number(n) if n == -4.0));
104 }
105
106 #[test]
107 fn test_div_builtin_integers_to_rational() {
108 let mut interp = setup_interpreter();
109
110 interp.push(Value::Integer(BigInt::from(1)));
112 interp.push(Value::Integer(BigInt::from(2)));
113 div_builtin(&mut interp).unwrap();
114
115 let result = interp.pop().unwrap();
116 if let Value::Rational(r) = result {
117 assert_eq!(*r.numer(), BigInt::from(1));
118 assert_eq!(*r.denom(), BigInt::from(2));
119 } else {
120 panic!("Expected Rational, got {:?}", result);
121 }
122
123 interp.push(Value::Integer(BigInt::from(10)));
125 interp.push(Value::Integer(BigInt::from(2)));
126 div_builtin(&mut interp).unwrap();
127
128 let result = interp.pop().unwrap();
129 assert!(matches!(result, Value::Int32(5)));
130 }
131
132 #[test]
133 fn test_div_builtin_mixed_types() {
134 let mut interp = setup_interpreter();
135
136 interp.push(Value::Integer(BigInt::from(10)));
138 interp.push(Value::Number(2.0));
139 div_builtin(&mut interp).unwrap();
140
141 let result = interp.pop().unwrap();
142 assert!(matches!(result, Value::Number(n) if n == 5.0));
143
144 interp.push(Value::Rational(BigRational::new(
146 BigInt::from(1),
147 BigInt::from(2),
148 )));
149 interp.push(Value::Number(2.0));
150 div_builtin(&mut interp).unwrap();
151
152 let result = interp.pop().unwrap();
153 assert!(matches!(result, Value::Number(n) if n == 0.25));
154 }
155
156 #[test]
157 fn test_div_builtin_rationals() {
158 let mut interp = setup_interpreter();
159
160 interp.push(Value::Rational(BigRational::new(
162 BigInt::from(1),
163 BigInt::from(2),
164 )));
165 interp.push(Value::Rational(BigRational::new(
166 BigInt::from(1),
167 BigInt::from(4),
168 )));
169 div_builtin(&mut interp).unwrap();
170
171 let result = interp.pop().unwrap();
172 assert!(matches!(result, Value::Int32(2)));
174 }
175
176 #[test]
177 fn test_div_builtin_division_by_zero() {
178 let mut interp = setup_interpreter();
179
180 interp.push(Value::Number(5.0));
182 interp.push(Value::Number(0.0));
183 let result = div_builtin(&mut interp);
184 assert!(matches!(result, Err(RuntimeError::DivisionByZero)));
185
186 interp.push(Value::Integer(BigInt::from(5)));
188 interp.push(Value::Integer(BigInt::from(0)));
189 let result = div_builtin(&mut interp);
190 assert!(matches!(result, Err(RuntimeError::DivisionByZero)));
191
192 interp.push(Value::Rational(BigRational::new(
194 BigInt::from(5),
195 BigInt::from(1),
196 )));
197 interp.push(Value::Rational(BigRational::new(
198 BigInt::from(0),
199 BigInt::from(1),
200 )));
201 let result = div_builtin(&mut interp);
202 assert!(matches!(result, Err(RuntimeError::DivisionByZero)));
203 }
204
205 #[test]
206 fn test_div_builtin_stack_underflow() {
207 let mut interp = setup_interpreter();
208
209 let result = div_builtin(&mut interp);
211 assert!(matches!(result, Err(RuntimeError::StackUnderflow)));
212
213 interp.push(Value::Number(5.0));
215 let result = div_builtin(&mut interp);
216 assert!(matches!(result, Err(RuntimeError::StackUnderflow)));
217 }
218
219 #[test]
220 fn test_div_builtin_type_error() {
221 let mut interp = setup_interpreter();
222
223 interp.push(Value::Number(5.0));
225 interp.push(Value::Null);
226 let result = div_builtin(&mut interp);
227 assert!(matches!(result, Err(RuntimeError::TypeError(_))));
228 }
229
230 #[test]
231 fn test_div_integer_by_integer_exact_division() {
232 let mut interp = setup_interpreter();
233
234 interp.push(Value::Integer(BigInt::from(100)));
238 interp.push(Value::Integer(BigInt::from(10)));
239 div_builtin(&mut interp).unwrap();
240 let result = interp.pop().unwrap();
241 assert!(matches!(result, Value::Int32(10)));
242
243 interp.push(Value::Integer(BigInt::from(1000)));
245 interp.push(Value::Integer(BigInt::from(100)));
246 div_builtin(&mut interp).unwrap();
247 let result = interp.pop().unwrap();
248 assert!(matches!(result, Value::Int32(10)));
249
250 interp.push(Value::Integer(BigInt::from(-20)));
252 interp.push(Value::Integer(BigInt::from(4)));
253 div_builtin(&mut interp).unwrap();
254 let result = interp.pop().unwrap();
255 assert!(matches!(result, Value::Int32(-5)));
256
257 interp.push(Value::Integer(BigInt::from(20)));
259 interp.push(Value::Integer(BigInt::from(-4)));
260 div_builtin(&mut interp).unwrap();
261 let result = interp.pop().unwrap();
262 assert!(matches!(result, Value::Int32(-5)));
263 }
264
265 #[test]
266 fn test_div_integer_by_integer_fractional_result() {
267 let mut interp = setup_interpreter();
268
269 interp.push(Value::Integer(BigInt::from(1)));
273 interp.push(Value::Integer(BigInt::from(3)));
274 div_builtin(&mut interp).unwrap();
275 let result = interp.pop().unwrap();
276 if let Value::Rational(r) = result {
277 assert_eq!(*r.numer(), BigInt::from(1));
278 assert_eq!(*r.denom(), BigInt::from(3));
279 } else {
280 panic!("Expected Rational, got {:?}", result);
281 }
282
283 interp.push(Value::Integer(BigInt::from(7)));
285 interp.push(Value::Integer(BigInt::from(4)));
286 div_builtin(&mut interp).unwrap();
287 let result = interp.pop().unwrap();
288 if let Value::Rational(r) = result {
289 assert_eq!(*r.numer(), BigInt::from(7));
290 assert_eq!(*r.denom(), BigInt::from(4));
291 } else {
292 panic!("Expected Rational, got {:?}", result);
293 }
294
295 interp.push(Value::Integer(BigInt::from(2)));
297 interp.push(Value::Integer(BigInt::from(5)));
298 div_builtin(&mut interp).unwrap();
299 let result = interp.pop().unwrap();
300 if let Value::Rational(r) = result {
301 assert_eq!(*r.numer(), BigInt::from(2));
302 assert_eq!(*r.denom(), BigInt::from(5));
303 } else {
304 panic!("Expected Rational, got {:?}", result);
305 }
306
307 interp.push(Value::Integer(BigInt::from(-3)));
309 interp.push(Value::Integer(BigInt::from(7)));
310 div_builtin(&mut interp).unwrap();
311 let result = interp.pop().unwrap();
312 if let Value::Rational(r) = result {
313 assert_eq!(*r.numer(), BigInt::from(-3));
314 assert_eq!(*r.denom(), BigInt::from(7));
315 } else {
316 panic!("Expected Rational, got {:?}", result);
317 }
318 }
319
320 #[test]
321 fn test_div_integer_by_integer_simplification() {
322 let mut interp = setup_interpreter();
323
324 interp.push(Value::Integer(BigInt::from(2)));
328 interp.push(Value::Integer(BigInt::from(4)));
329 div_builtin(&mut interp).unwrap();
330 let result = interp.pop().unwrap();
331 if let Value::Rational(r) = result {
332 assert_eq!(*r.numer(), BigInt::from(1));
333 assert_eq!(*r.denom(), BigInt::from(2));
334 } else {
335 panic!("Expected Rational, got {:?}", result);
336 }
337
338 interp.push(Value::Integer(BigInt::from(6)));
340 interp.push(Value::Integer(BigInt::from(9)));
341 div_builtin(&mut interp).unwrap();
342 let result = interp.pop().unwrap();
343 if let Value::Rational(r) = result {
344 assert_eq!(*r.numer(), BigInt::from(2));
345 assert_eq!(*r.denom(), BigInt::from(3));
346 } else {
347 panic!("Expected Rational, got {:?}", result);
348 }
349
350 interp.push(Value::Integer(BigInt::from(15)));
352 interp.push(Value::Integer(BigInt::from(25)));
353 div_builtin(&mut interp).unwrap();
354 let result = interp.pop().unwrap();
355 if let Value::Rational(r) = result {
356 assert_eq!(*r.numer(), BigInt::from(3));
357 assert_eq!(*r.denom(), BigInt::from(5));
358 } else {
359 panic!("Expected Rational, got {:?}", result);
360 }
361 }
362
363 #[test]
364 fn test_div_mixed_integer_rational() {
365 let mut interp = setup_interpreter();
366
367 interp.push(Value::Integer(BigInt::from(10)));
370 interp.push(Value::Rational(BigRational::new(
371 BigInt::from(1),
372 BigInt::from(2),
373 )));
374 div_builtin(&mut interp).unwrap();
375 let result = interp.pop().unwrap();
376 assert!(matches!(result, Value::Int32(20)));
377
378 interp.push(Value::Rational(BigRational::new(
381 BigInt::from(3),
382 BigInt::from(4),
383 )));
384 interp.push(Value::Integer(BigInt::from(2)));
385 div_builtin(&mut interp).unwrap();
386 let result = interp.pop().unwrap();
387 if let Value::Rational(r) = result {
388 assert_eq!(*r.numer(), BigInt::from(3));
389 assert_eq!(*r.denom(), BigInt::from(8));
390 } else {
391 panic!("Expected Rational, got {:?}", result);
392 }
393 }
394
395 #[test]
396 fn test_div_rational_non_simplifying() {
397 let mut interp = setup_interpreter();
398
399 interp.push(Value::Rational(BigRational::new(
402 BigInt::from(2),
403 BigInt::from(3),
404 )));
405 interp.push(Value::Rational(BigRational::new(
406 BigInt::from(4),
407 BigInt::from(5),
408 )));
409 div_builtin(&mut interp).unwrap();
410 let result = interp.pop().unwrap();
411 if let Value::Rational(r) = result {
412 assert_eq!(*r.numer(), BigInt::from(5));
413 assert_eq!(*r.denom(), BigInt::from(6));
414 } else {
415 panic!("Expected Rational, got {:?}", result);
416 }
417 }
418
419 #[test]
420 fn test_div_mixed_number_integer() {
421 let mut interp = setup_interpreter();
422
423 interp.push(Value::Number(10.5));
426 interp.push(Value::Integer(BigInt::from(2)));
427 div_builtin(&mut interp).unwrap();
428 let result = interp.pop().unwrap();
429 assert!(matches!(result, Value::Number(n) if n == 5.25));
430
431 interp.push(Value::Integer(BigInt::from(15)));
434 interp.push(Value::Number(2.0));
435 div_builtin(&mut interp).unwrap();
436 let result = interp.pop().unwrap();
437 assert!(matches!(result, Value::Number(n) if n == 7.5));
438 }
439
440 #[test]
441 fn test_div_mixed_number_rational() {
442 let mut interp = setup_interpreter();
443
444 interp.push(Value::Number(8.0));
447 interp.push(Value::Rational(BigRational::new(
448 BigInt::from(1),
449 BigInt::from(2),
450 )));
451 div_builtin(&mut interp).unwrap();
452 let result = interp.pop().unwrap();
453 assert!(matches!(result, Value::Number(n) if n == 16.0));
454
455 interp.push(Value::Rational(BigRational::new(
458 BigInt::from(3),
459 BigInt::from(4),
460 )));
461 interp.push(Value::Number(2.0));
462 div_builtin(&mut interp).unwrap();
463 let result = interp.pop().unwrap();
464 assert!(matches!(result, Value::Number(n) if (n - 0.375).abs() < 1e-10));
465 }
466
467 #[test]
468 #[cfg(feature = "complex_numbers")]
469 fn test_div_complex_numbers() {
470 use num_complex::Complex64;
471
472 let mut interp = setup_interpreter();
473
474 interp.push(Value::Complex(Complex64::new(4.0, 2.0)));
476 interp.push(Value::Complex(Complex64::new(1.0, 1.0)));
477 div_builtin(&mut interp).unwrap();
478 let result = interp.pop().unwrap();
479 if let Value::Complex(c) = result {
480 assert!((c.re - 3.0).abs() < 1e-10);
481 assert!((c.im - (-1.0)).abs() < 1e-10);
482 } else {
483 panic!("Expected Complex, got {:?}", result);
484 }
485 }
486
487 #[test]
488 fn test_div_large_integers() {
489 let mut interp = setup_interpreter();
490
491 let large1 = BigInt::parse_bytes(b"123456789012345678901234567891", 10).unwrap();
494 let large2 = BigInt::parse_bytes(b"987654321098765432109876543211", 10).unwrap();
495
496 interp.push(Value::Integer(large1.clone()));
497 interp.push(Value::Integer(large2.clone()));
498 div_builtin(&mut interp).unwrap();
499
500 let result = interp.pop().unwrap();
501 assert!(matches!(result, Value::Rational(_)));
504 }
505}