rateslib/dual/dual_ops/
rem.rs

1use crate::dual::dual::{Dual, Dual2};
2use crate::dual::enums::Number;
3use auto_ops::impl_op_ex;
4use std::sync::Arc;
5
6impl_op_ex!(% |a: &Dual, b: &f64| -> Dual { Dual {vars: Arc::clone(&a.vars), real: a.real % b, dual: a.dual.clone()} });
7impl_op_ex!(% |a: &f64, b: &Dual| -> Dual { Dual::new(*a, Vec::new()) % b });
8impl_op_ex!(% |a: &Dual2, b: &f64| -> Dual2 {
9    Dual2 {vars: Arc::clone(&a.vars), real: a.real % b, dual: a.dual.clone(), dual2: a.dual2.clone()}
10});
11impl_op_ex!(% |a: &f64, b: &Dual2| -> Dual2 {
12    Dual2::new(*a, Vec::new()) % b }
13);
14
15// impl REM for Dual
16impl_op_ex!(% |a: &Dual, b: &Dual| -> Dual {
17    let d = f64::trunc(a.real / b.real);
18    a - d * b
19});
20
21// impl Rem for Dual2
22impl_op_ex!(% |a: &Dual2, b: &Dual2| -> Dual2 {
23    let d = f64::trunc(a.real / b.real);
24    a - d * b
25});
26
27// Rem for Number
28impl_op_ex!(% |a: &Number, b: &Number| -> Number {
29    match (a,b) {
30        (Number::F64(f), Number::F64(f2)) => Number::F64(f % f2),
31        (Number::F64(f), Number::Dual(d2)) => Number::Dual(f % d2),
32        (Number::F64(f), Number::Dual2(d2)) => Number::Dual2(f % d2),
33        (Number::Dual(d), Number::F64(f2)) => Number::Dual(d % f2),
34        (Number::Dual(d), Number::Dual(d2)) => Number::Dual(d % d2),
35        (Number::Dual(_), Number::Dual2(_)) => panic!("Cannot mix dual types: Dual % Dual2"),
36        (Number::Dual2(d), Number::F64(f2)) => Number::Dual2(d % f2),
37        (Number::Dual2(_), Number::Dual(_)) => panic!("Cannot mix dual types: Dual2 % Dual"),
38        (Number::Dual2(d), Number::Dual2(d2)) => Number::Dual2(d % d2),
39    }
40});
41
42// Rem for Number
43impl_op_ex!(% |a: &Number, b: &f64| -> Number {
44    match a {
45        Number::F64(f) => Number::F64(f % b),
46        Number::Dual(d) => Number::Dual(d % b),
47        Number::Dual2(d) => Number::Dual2(d % b),
48    }
49});
50
51// Rem for Number
52impl_op_ex!(% |a: &f64, b: &Number| -> Number {
53    match b {
54        Number::F64(f) => Number::F64(a % f),
55        Number::Dual(d) => Number::Dual(a % d),
56        Number::Dual2(d) => Number::Dual2(a % d),
57    }
58});
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    fn rem_() {
66        let d1 = Dual::try_new(10.0, vec!["x".to_string()], vec![2.0]).unwrap();
67        let d2 = Dual::new(3.0, vec!["x".to_string()]);
68        let result = d1 % d2;
69        let expected = Dual::try_new(1.0, vec!["x".to_string()], vec![-1.0]).unwrap();
70        assert_eq!(result, expected);
71    }
72
73    #[test]
74    fn rem_f64_() {
75        let d1 = Dual::try_new(10.0, vec!["x".to_string()], vec![2.0]).unwrap();
76        let result = &d1 % 3.0_f64;
77        assert_eq!(
78            result,
79            Dual::try_new(1.0, vec!["x".to_string()], vec![2.0]).unwrap()
80        );
81
82        let result = 11.0_f64 % d1;
83        assert_eq!(
84            result,
85            Dual::try_new(1.0, vec!["x".to_string()], vec![-2.0]).unwrap()
86        );
87    }
88
89    #[test]
90    fn rem_2() {
91        let d1 = Dual2::try_new(10.0, vec!["x".to_string()], vec![2.0], vec![]).unwrap();
92        let d2 = Dual2::new(3.0, vec!["x".to_string()]);
93        let result = d1 % d2;
94        let expected = Dual2::try_new(1.0, vec!["x".to_string()], vec![-1.0], vec![]).unwrap();
95        assert_eq!(result, expected);
96    }
97
98    #[test]
99    fn rem_f64_2() {
100        let d1 = Dual2::try_new(10.0, vec!["x".to_string()], vec![2.0], vec![]).unwrap();
101        let result = &d1 % 3.0_f64;
102        assert_eq!(
103            result,
104            Dual2::try_new(1.0, vec!["x".to_string()], vec![2.0], vec![]).unwrap()
105        );
106
107        let result = 11.0_f64 % d1;
108        assert_eq!(
109            result,
110            Dual2::try_new(1.0, vec!["x".to_string()], vec![-2.0], vec![]).unwrap()
111        );
112    }
113
114    #[test]
115    fn test_enum() {
116        let f = Number::F64(4.0);
117        let d = Number::Dual(Dual::new(3.0, vec!["x".to_string()]));
118        assert_eq!(
119            &f % &d,
120            Number::Dual(Dual::try_new(1.0, vec!["x".to_string()], vec![-1.0]).unwrap())
121        );
122
123        assert_eq!(
124            &d % &d,
125            Number::Dual(Dual::try_new(0.0, vec!["x".to_string()], vec![0.0]).unwrap())
126        );
127    }
128
129    #[test]
130    #[should_panic]
131    fn test_enum_panic() {
132        let d = Number::Dual2(Dual2::new(2.0, vec!["y".to_string()]));
133        let d2 = Number::Dual(Dual::new(3.0, vec!["x".to_string()]));
134        let _ = d % d2;
135    }
136
137    #[test]
138    fn test_enum_f64() {
139        let d = Number::Dual(Dual::new(3.0, vec!["x".to_string()]));
140        let res = 2.0_f64 % d;
141        assert_eq!(
142            res,
143            Number::Dual(2.0 % Dual::new(3.0, vec!["x".to_string()]))
144        );
145
146        let d = Number::Dual(Dual::new(3.0, vec!["x".to_string()]));
147        let res = d % 2.0_f64;
148        assert_eq!(
149            res,
150            Number::Dual(Dual::new(3.0, vec!["x".to_string()]) % 2.0)
151        );
152    }
153}