1use num_traits::{Float, Num, NumCast, One, ToPrimitive, Zero};
2use std::cmp::Ordering;
3use std::num::FpCategory;
4use std::ops::{
5 Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign,
6};
7
8#[cfg(feature = "trig")]
9use trig::Trig;
10
11#[derive(Debug, Clone, Copy)]
13pub struct Dual {
14 real: f64,
16
17 dual: f64,
19}
20
21impl Dual {
22 pub fn new(real: f64, dual: f64) -> Dual {
41 Dual { real, dual }
42 }
43
44 pub fn get_real(self) -> f64 {
59 self.real
60 }
61
62 pub fn get_dual(self) -> f64 {
77 self.dual
78 }
79}
80
81impl Add for Dual {
97 type Output = Dual;
98 fn add(self, rhs: Dual) -> Dual {
99 Dual::new(self.real + rhs.real, self.dual + rhs.dual)
100 }
101}
102
103impl Sub for Dual {
105 type Output = Dual;
106 fn sub(self, rhs: Dual) -> Dual {
107 Dual::new(self.real - rhs.real, self.dual - rhs.dual)
108 }
109}
110
111impl Mul for Dual {
113 type Output = Dual;
114 fn mul(self, rhs: Dual) -> Dual {
115 Dual::new(
116 self.real * rhs.real,
117 self.dual * rhs.real + self.real * rhs.dual,
118 )
119 }
120}
121
122impl Div for Dual {
124 type Output = Dual;
125 fn div(self, rhs: Dual) -> Dual {
126 Dual::new(
127 self.real / rhs.real,
128 (self.dual * rhs.real - self.real * rhs.dual) / rhs.real.powi(2),
129 )
130 }
131}
132
133impl Rem for Dual {
135 type Output = Self;
136 fn rem(self, rhs: Self) -> Self::Output {
137 Dual::new(
138 self.real % rhs.real,
139 self.dual - (self.real / rhs.real).trunc() * rhs.dual,
140 )
141 }
142}
143
144impl PartialEq for Dual {
161 fn eq(&self, other: &Self) -> bool {
162 self.real == other.real && self.dual == other.dual
163 }
164}
165
166impl Zero for Dual {
167 fn zero() -> Self {
168 Dual::new(0.0, 0.0)
169 }
170 fn is_zero(&self) -> bool {
171 self.real.is_zero() && self.dual.is_zero()
172 }
173}
174
175impl One for Dual {
176 fn one() -> Self {
177 Dual::new(1.0, 0.0)
178 }
179}
180
181impl Num for Dual {
182 type FromStrRadixErr = <f64 as Num>::FromStrRadixErr;
183 fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
184 f64::from_str_radix(str, radix).map(|re| Dual::new(re, 0.0))
185 }
186}
187
188impl ToPrimitive for Dual {
204 fn to_i64(&self) -> Option<i64> {
205 self.real.to_i64()
206 }
207 fn to_u64(&self) -> Option<u64> {
208 self.real.to_u64()
209 }
210 fn to_f64(&self) -> Option<f64> {
211 Some(self.real)
212 }
213}
214
215impl NumCast for Dual {
226 fn from<T: ToPrimitive>(n: T) -> Option<Self> {
227 n.to_f64().map(|re| Dual::new(re, 0.0))
228 }
229}
230
231impl PartialOrd for Dual {
244 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
245 self.real.partial_cmp(&other.real)
246 }
247}
248
249impl Neg for Dual {
250 type Output = Self;
251 fn neg(self) -> Self::Output {
252 Dual::new(-self.real, -self.dual)
253 }
254}
255
256impl Float for Dual {
257 fn nan() -> Self {
258 Dual::new(f64::nan(), f64::nan())
259 }
260
261 fn infinity() -> Self {
262 Dual::new(f64::infinity(), f64::infinity())
263 }
264
265 fn neg_infinity() -> Self {
266 Dual::new(f64::neg_infinity(), f64::neg_infinity())
267 }
268
269 fn neg_zero() -> Self {
270 Dual::new(f64::neg_zero(), f64::neg_zero())
271 }
272
273 fn min_value() -> Self {
274 Dual::new(f64::min_value(), f64::min_value())
275 }
276
277 fn min_positive_value() -> Self {
278 Dual::new(f64::min_positive_value(), f64::min_positive_value())
279 }
280
281 fn max_value() -> Self {
282 Dual::new(f64::max_value(), f64::max_value())
283 }
284
285 fn is_nan(self) -> bool {
286 self.real.is_nan()
287 }
288
289 fn is_infinite(self) -> bool {
290 self.real.is_infinite()
291 }
292
293 fn is_finite(self) -> bool {
294 self.real.is_finite()
295 }
296
297 fn is_normal(self) -> bool {
298 self.real.is_normal()
299 }
300
301 fn classify(self) -> FpCategory {
302 self.real.classify()
303 }
304
305 fn floor(self) -> Self {
306 Dual::new(self.real.floor(), 0.0)
307 }
308
309 fn ceil(self) -> Self {
310 Dual::new(self.real.ceil(), 0.0)
311 }
312
313 fn round(self) -> Self {
314 Dual::new(self.real.round(), 0.0)
315 }
316
317 fn trunc(self) -> Self {
318 Dual::new(self.real.trunc(), 0.0)
319 }
320
321 fn fract(self) -> Self {
322 Dual::new(self.real.fract(), self.dual)
323 }
324
325 fn abs(self) -> Self {
326 Dual::new(self.real.abs(), self.dual * self.real.signum())
327 }
328
329 fn signum(self) -> Self {
330 Dual::new(self.real.signum(), f64::zero())
331 }
332
333 fn is_sign_positive(self) -> bool {
334 self.real.is_sign_positive()
335 }
336
337 fn is_sign_negative(self) -> bool {
338 self.real.is_sign_negative()
339 }
340
341 fn mul_add(self, a: Self, b: Self) -> Self {
342 Dual::new(
343 self.real.mul_add(a.real, b.real),
344 self.real * a.dual + self.dual * a.real + b.dual,
345 )
346 }
347
348 fn recip(self) -> Self {
349 Dual::new(self.real.recip(), -self.dual / self.real.powi(2))
350 }
351
352 fn powi(self, n: i32) -> Self {
353 if n == 0 {
354 Dual::one()
355 } else {
356 Dual::new(
357 self.real.powi(n),
358 (n as f64) * self.dual * self.real.powi(n - 1),
359 )
360 }
361 }
362
363 fn powf(self, n: Self) -> Self {
365 (self.ln() * n).exp()
366 }
367
368 fn sqrt(self) -> Self {
369 let sqrt_re = self.real.sqrt();
370 Dual::new(sqrt_re, self.dual / (2.0 * sqrt_re))
371 }
372
373 fn exp(self) -> Self {
374 let exp_re = self.real.exp();
375 Dual::new(exp_re, exp_re * self.dual)
376 }
377
378 fn exp2(self) -> Self {
379 let exp2_re = self.real.exp2();
380 Dual::new(exp2_re, exp2_re * std::f64::consts::LN_2 * self.dual)
381 }
382
383 fn ln(self) -> Self {
384 Dual::new(self.real.ln(), self.dual / self.real)
385 }
386
387 fn log(self, base: Self) -> Self {
388 Dual::new(
389 self.real.log(base.real),
390 self.dual / (self.real * base.real.ln()),
391 )
392 }
393
394 fn log2(self) -> Self {
395 Dual::new(
396 self.real.ln() / std::f64::consts::LN_2,
397 self.dual / (self.real * std::f64::consts::LN_2),
398 )
399 }
400
401 fn log10(self) -> Self {
402 Dual::new(
403 self.real.ln() / std::f64::consts::LN_10,
404 self.dual / (self.real * std::f64::consts::LN_10),
405 )
406 }
407
408 fn max(self, other: Self) -> Self {
409 if self.real > other.real {
410 self
411 } else {
412 other
413 }
414 }
415
416 fn min(self, other: Self) -> Self {
417 if self.real < other.real {
418 self
419 } else {
420 other
421 }
422 }
423
424 #[allow(deprecated)]
425 fn abs_sub(self, other: Self) -> Self {
426 if self.real > other.real {
427 self - other
428 } else {
429 Self::zero()
430 }
431 }
432
433 fn cbrt(self) -> Self {
434 let cbrt_re = self.real.cbrt();
435 Dual::new(cbrt_re, self.dual / (3.0 * cbrt_re.powi(2)))
436 }
437
438 fn hypot(self, other: Self) -> Self {
439 let hypot_real = (self.real.powi(2) + other.real.powi(2)).sqrt();
440 Dual::new(
441 hypot_real,
442 (self.real * self.dual + other.real * other.dual) / hypot_real,
443 )
444 }
445
446 fn sin(self) -> Self {
447 Dual::new(self.real.sin(), self.real.cos() * self.dual)
448 }
449
450 fn cos(self) -> Self {
451 Dual::new(self.real.cos(), -self.real.sin() * self.dual)
452 }
453
454 fn tan(self) -> Self {
455 let re_tan = self.real.tan();
456 Dual::new(re_tan, self.dual / (self.real.cos().powi(2)))
457 }
458
459 fn asin(self) -> Self {
460 Dual::new(
461 self.real.asin(),
462 self.dual / (1.0 - self.real.powi(2)).sqrt(),
463 )
464 }
465
466 fn acos(self) -> Self {
467 Dual::new(
468 self.real.acos(),
469 -self.dual / (1.0 - self.real.powi(2)).sqrt(),
470 )
471 }
472
473 fn atan(self) -> Self {
474 Dual::new(self.real.atan(), self.dual / (1.0 + self.real.powi(2)))
475 }
476
477 fn atan2(self, other: Self) -> Self {
478 Dual::new(
479 self.real.atan2(other.real),
480 (self.dual * other.real - self.real * other.dual)
481 / (self.real.powi(2) + other.real.powi(2)),
482 )
483 }
484
485 fn sin_cos(self) -> (Self, Self) {
486 (
487 Dual::new(self.real.sin(), self.real.cos() * self.dual),
488 Dual::new(self.real.cos(), -self.real.sin() * self.dual),
489 )
490 }
491
492 fn exp_m1(self) -> Self {
493 let exp_re = self.real.exp();
494 Dual::new(exp_re - 1.0, self.dual * exp_re)
495 }
496
497 fn ln_1p(self) -> Self {
498 Dual::new(self.real.ln_1p(), self.dual / (1.0 + self.real))
499 }
500
501 fn sinh(self) -> Self {
502 Dual::new(self.real.sinh(), self.dual * self.real.cosh())
503 }
504
505 fn cosh(self) -> Self {
506 Dual::new(self.real.cosh(), self.dual * self.real.sinh())
507 }
508
509 fn tanh(self) -> Self {
510 let tanh_re = self.real.tanh();
511 Dual::new(tanh_re, self.dual * (1.0 - tanh_re.powi(2)))
512 }
513
514 fn asinh(self) -> Self {
515 Dual::new(
516 self.real.asinh(),
517 self.dual / (self.real.powi(2) + 1.0).sqrt(),
518 )
519 }
520
521 fn acosh(self) -> Self {
522 Dual::new(
523 self.real.acosh(),
524 self.dual / (self.real.powi(2) - 1.0).sqrt(),
525 )
526 }
527
528 fn atanh(self) -> Self {
529 Dual::new(self.real.atanh(), self.dual / (1.0 - self.real.powi(2)))
530 }
531
532 fn integer_decode(self) -> (u64, i16, i8) {
535 self.real.integer_decode()
536 }
537}
538
539impl AddAssign for Dual {
566 fn add_assign(&mut self, other: Dual) {
567 self.real += other.real;
568 self.dual += other.dual;
569 }
570}
571
572impl SubAssign for Dual {
574 fn sub_assign(&mut self, other: Dual) {
575 self.real -= other.real;
576 self.dual -= other.dual;
577 }
578}
579
580impl MulAssign for Dual {
582 fn mul_assign(&mut self, other: Dual) {
583 self.dual = self.dual * other.real + self.real * other.dual;
584 self.real *= other.real;
585 }
586}
587
588impl DivAssign for Dual {
590 fn div_assign(&mut self, other: Dual) {
591 self.dual = (self.dual * other.real - self.real * other.dual) / other.real.powi(2);
592 self.real /= other.real;
593 }
594}
595
596impl RemAssign for Dual {
598 fn rem_assign(&mut self, rhs: Self) {
599 self.dual -= (self.real / rhs.real).floor() * rhs.dual;
600 self.real %= rhs.real;
601 }
602}
603
604impl Add<f64> for Dual {
606 type Output = Dual;
607 fn add(self, rhs: f64) -> Dual {
608 Dual::new(self.real + rhs, self.dual)
609 }
610}
611
612impl Sub<f64> for Dual {
614 type Output = Dual;
615 fn sub(self, rhs: f64) -> Dual {
616 Dual::new(self.real - rhs, self.dual)
617 }
618}
619
620impl Mul<f64> for Dual {
622 type Output = Dual;
623 fn mul(self, rhs: f64) -> Dual {
624 Dual::new(self.real * rhs, self.dual * rhs)
625 }
626}
627
628impl Div<f64> for Dual {
630 type Output = Dual;
631 fn div(self, rhs: f64) -> Dual {
632 Dual::new(self.real / rhs, self.dual / rhs)
633 }
634}
635
636impl Rem<f64> for Dual {
638 type Output = Dual;
639 fn rem(self, rhs: f64) -> Self::Output {
640 let rem_real = self.real % rhs;
641 let rem_dual = if self.real % rhs == 0.0 {
642 0.0
643 } else {
644 self.dual
645 };
646 Dual::new(rem_real, rem_dual)
647 }
648}
649
650impl AddAssign<f64> for Dual {
652 fn add_assign(&mut self, rhs: f64) {
653 self.real += rhs;
654 }
655}
656
657impl SubAssign<f64> for Dual {
659 fn sub_assign(&mut self, rhs: f64) {
660 self.real -= rhs;
661 }
662}
663
664impl MulAssign<f64> for Dual {
666 fn mul_assign(&mut self, rhs: f64) {
667 self.real *= rhs;
668 self.dual *= rhs;
669 }
670}
671
672impl DivAssign<f64> for Dual {
674 fn div_assign(&mut self, rhs: f64) {
675 self.real /= rhs;
676 self.dual /= rhs;
677 }
678}
679
680impl RemAssign<f64> for Dual {
682 fn rem_assign(&mut self, rhs: f64) {
683 self.real = self.real % rhs;
684 if self.real == 0.0 {
685 self.dual = 0.0;
686 }
687 }
688}
689
690impl Add<Dual> for f64 {
696 type Output = Dual;
697 fn add(self, rhs: Dual) -> Dual {
698 Dual::new(self + rhs.real, rhs.dual)
699 }
700}
701
702impl Sub<Dual> for f64 {
704 type Output = Dual;
705 fn sub(self, rhs: Dual) -> Dual {
706 Dual::new(self - rhs.real, rhs.dual)
707 }
708}
709
710impl Mul<Dual> for f64 {
712 type Output = Dual;
713 fn mul(self, rhs: Dual) -> Dual {
714 Dual::new(self * rhs.real, self * rhs.dual)
715 }
716}
717
718impl Div<Dual> for f64 {
720 type Output = Dual;
721 fn div(self, rhs: Dual) -> Dual {
722 Dual::new(self / rhs.real, -self * rhs.dual / rhs.real.powi(2))
723 }
724}
725
726impl Rem<Dual> for f64 {
728 type Output = Dual;
729 fn rem(self, rhs: Dual) -> Dual {
730 Dual::new(self % rhs.real, -(self / rhs.real).floor() * rhs.dual)
731 }
732}
733
734#[cfg(feature = "trig")]
739impl Trig for Dual {
740 fn sin(&self) -> Dual {
741 <Dual as Float>::sin(*self)
742 }
743 fn cos(&self) -> Dual {
744 <Dual as Float>::cos(*self)
745 }
746 fn tan(&self) -> Dual {
747 <Dual as Float>::tan(*self)
748 }
749 fn csc(&self) -> Dual {
750 1.0 / self.sin()
751 }
752 fn sec(&self) -> Dual {
753 1.0 / self.cos()
754 }
755 fn cot(&self) -> Dual {
756 1.0 / self.tan()
757 }
758 fn asin(&self) -> Dual {
759 <Dual as Float>::asin(*self)
760 }
761 fn acos(&self) -> Dual {
762 <Dual as Float>::acos(*self)
763 }
764 fn atan(&self) -> Dual {
765 <Dual as Float>::atan(*self)
766 }
767 fn atan2(&self, other: &Dual) -> Dual {
768 <Dual as Float>::atan2(*self, *other)
769 }
770 fn acsc(&self) -> Dual {
771 (Dual::new(1.0, 0.0) / *self).asin()
772 }
773 fn asec(&self) -> Dual {
774 (Dual::new(1.0, 0.0) / *self).acos()
775 }
776 fn acot(&self) -> Dual {
777 (Dual::new(1.0, 0.0) / *self).atan()
778 }
779 fn deg2rad(&self) -> Dual {
780 *self * Dual::new(std::f64::consts::PI / 180.0, 0.0)
781 }
782 fn rad2deg(&self) -> Dual {
783 *self * Dual::new(180.0 / std::f64::consts::PI, 0.0)
784 }
785 fn sind(&self) -> Dual {
786 self.deg2rad().sin()
787 }
788 fn cosd(&self) -> Dual {
789 self.deg2rad().cos()
790 }
791 fn tand(&self) -> Dual {
792 self.deg2rad().tan()
793 }
794 fn cscd(&self) -> Dual {
795 self.deg2rad().csc()
796 }
797 fn secd(&self) -> Dual {
798 self.deg2rad().sec()
799 }
800 fn cotd(&self) -> Dual {
801 self.deg2rad().cot()
802 }
803 fn asind(&self) -> Dual {
804 self.asin().rad2deg()
805 }
806 fn acosd(&self) -> Dual {
807 self.acos().rad2deg()
808 }
809 fn atand(&self) -> Dual {
810 self.atan().rad2deg()
811 }
812 fn atan2d(&self, other: &Dual) -> Dual {
813 self.atan2(other).rad2deg()
814 }
815 fn acscd(&self) -> Dual {
816 self.acsc().rad2deg()
817 }
818 fn asecd(&self) -> Dual {
819 self.asec().rad2deg()
820 }
821 fn acotd(&self) -> Dual {
822 self.acot().rad2deg()
823 }
824 fn sinh(&self) -> Dual {
825 <Dual as Float>::sinh(*self)
826 }
827 fn cosh(&self) -> Dual {
828 <Dual as Float>::cosh(*self)
829 }
830 fn tanh(&self) -> Dual {
831 <Dual as Float>::tanh(*self)
832 }
833 fn csch(&self) -> Dual {
834 1.0 / self.sinh()
835 }
836 fn sech(&self) -> Dual {
837 1.0 / self.cosh()
838 }
839 fn coth(&self) -> Dual {
840 1.0 / self.tanh()
841 }
842 fn asinh(&self) -> Dual {
843 <Dual as Float>::asinh(*self)
844 }
845 fn acosh(&self) -> Dual {
846 <Dual as Float>::acosh(*self)
847 }
848 fn atanh(&self) -> Dual {
849 <Dual as Float>::atanh(*self)
850 }
851 fn acsch(&self) -> Dual {
852 (Dual::new(1.0, 0.0) / *self).asinh()
853 }
854 fn asech(&self) -> Dual {
855 (Dual::new(1.0, 0.0) / *self).acosh()
856 }
857 fn acoth(&self) -> Dual {
858 (Dual::new(1.0, 0.0) / *self).atanh()
859 }
860}
861
862#[cfg(test)]
867mod tests {
868 use super::*;
869 use linalg_traits::Scalar;
870 use numtest::*;
871 use std::f64::consts::{E, FRAC_PI_4, FRAC_PI_6};
872
873 impl Compare for Dual {
875 fn is_equal(&self, other: Self) -> bool {
876 let real_equal = self.get_real().is_equal(other.get_real());
877 let dual_equal = self.get_dual().is_equal(other.get_dual());
878 real_equal & dual_equal
879 }
880 fn is_equal_to_decimal(&self, other: Self, decimal: i32) -> (bool, i32) {
881 let (real_equal, real_decimal) = self
882 .get_real()
883 .is_equal_to_decimal(other.get_real(), decimal);
884 let (dual_equal, dual_decimal) = self
885 .get_dual()
886 .is_equal_to_decimal(other.get_dual(), decimal);
887 (real_equal & dual_equal, real_decimal.min(dual_decimal))
888 }
889 fn is_equal_to_atol(&self, other: Self, atol: Self) -> (bool, Self) {
890 let (real_equal, real_abs_diff) = self
891 .get_real()
892 .is_equal_to_atol(other.get_real(), atol.get_real());
893 let (dual_equal, dual_abs_diff) = self
894 .get_dual()
895 .is_equal_to_atol(other.get_dual(), atol.get_dual());
896 (
897 real_equal & dual_equal,
898 Dual::new(real_abs_diff, dual_abs_diff),
899 )
900 }
901 fn is_equal_to_rtol(&self, other: Self, rtol: Self) -> (bool, Self) {
902 let (real_equal, real_rel_diff) = self
903 .get_real()
904 .is_equal_to_rtol(other.get_real(), rtol.get_real());
905 let (dual_equal, dual_rel_diff) = self
906 .get_dual()
907 .is_equal_to_rtol(other.get_dual(), rtol.get_dual());
908 (
909 real_equal & dual_equal,
910 Dual::new(real_rel_diff, dual_rel_diff),
911 )
912 }
913 }
914
915 #[test]
916 fn test_new() {
917 let num1 = Dual::new(1.0, 2.0);
918 let num2 = Dual {
919 real: 1.0,
920 dual: 2.0,
921 };
922 assert_eq!(num1.real, num2.real);
923 assert_eq!(num1.dual, num2.dual);
924 }
925
926 #[test]
927 fn test_get_real() {
928 let num = Dual::new(1.0, 2.0);
929 assert_eq!(num.get_real(), 1.0);
930 }
931
932 #[test]
933 fn test_get_dual() {
934 let num = Dual::new(1.0, 2.0);
935 assert_eq!(num.get_dual(), 2.0);
936 }
937
938 #[test]
939 fn test_add_dual_dual() {
940 assert_eq!(
941 Dual::new(1.0, 2.0) + Dual::new(3.0, 4.0),
942 Dual::new(4.0, 6.0)
943 );
944 }
945
946 #[test]
947 fn test_sub_dual_dual() {
948 assert_eq!(
949 Dual::new(1.0, 2.0) - Dual::new(4.0, 3.0),
950 Dual::new(-3.0, -1.0)
951 );
952 }
953
954 #[test]
955 fn test_mul_dual_dual() {
956 assert_eq!(
957 Dual::new(1.0, 2.0) * Dual::new(3.0, -4.0),
958 Dual::new(3.0, 2.0)
959 );
960 }
961
962 #[test]
963 fn test_div_dual_dual() {
964 assert_eq!(
965 Dual::new(1.0, 2.0) / Dual::new(3.0, 4.0),
966 Dual::new(1.0 / 3.0, 2.0 / 9.0)
967 );
968 }
969
970 #[test]
971 fn test_rem_dual_dual() {
972 assert_eq!(
974 Dual::new(5.0, 2.0) % Dual::new(3.0, 4.0),
975 Dual::new(2.0, -2.0)
976 );
977
978 let a = Dual::new(5.0, 2.0);
981 let n = Dual::new(3.0, 5.0);
982 assert_eq!(a % n, a - n * (a / n).trunc());
983 }
984
985 #[test]
986 fn test_zero() {
987 assert_eq!(Dual::zero(), Dual::new(0.0, 0.0));
989
990 assert!(Dual::zero().is_zero());
992 assert!(Dual::new(0.0, 0.0).is_zero());
993
994 assert_eq!(Dual::zero() * Dual::new(1.0, 2.0), Dual::zero());
996 }
997
998 #[test]
999 fn test_one() {
1000 assert_eq!(Dual::one(), Dual::new(1.0, 0.0));
1002
1003 assert_eq!(Dual::one() * Dual::new(1.0, 2.0), Dual::new(1.0, 2.0));
1005
1006 assert_eq!(Dual::one() * 5.0, Dual::new(5.0, 0.0));
1008 }
1009
1010 #[test]
1011 fn test_from_str_radix() {
1012 assert_eq!(
1013 Dual::from_str_radix("2.125", 10).unwrap(),
1014 Dual::new(2.125, 0.0)
1015 );
1016 }
1017
1018 #[test]
1019 fn test_to_i64() {
1020 assert_eq!(Dual::new(1.0, 2.0).to_i64().unwrap(), 1_i64);
1021 assert_eq!(Dual::new(-1.0, 2.0).to_i64().unwrap(), -1_i64);
1022 }
1023
1024 #[test]
1025 fn test_to_u64() {
1026 assert_eq!(Dual::new(1.0, 2.0).to_u64().unwrap(), 1_u64);
1027 assert!(Dual::new(-1.0, 2.0).to_u64().is_none());
1028 }
1029
1030 #[test]
1031 fn test_to_f64() {
1032 assert_eq!(Dual::new(1.0, 2.0).to_f64().unwrap(), 1.0_f64);
1033 assert_eq!(Dual::new(-1.0, 2.0).to_f64().unwrap(), -1.0_f64);
1034 }
1035
1036 #[test]
1037 fn test_from_i64() {
1038 assert_eq!(<Dual as NumCast>::from(1_i64).unwrap(), Dual::new(1.0, 0.0));
1039 assert_eq!(
1040 <Dual as NumCast>::from(-1_i64).unwrap(),
1041 Dual::new(-1.0, 0.0)
1042 );
1043 }
1044
1045 #[test]
1046 fn test_from_u64() {
1047 assert_eq!(<Dual as NumCast>::from(1_u64).unwrap(), Dual::new(1.0, 0.0));
1048 }
1049
1050 #[test]
1051 fn test_from_f64() {
1052 assert_eq!(<Dual as NumCast>::from(1_f64).unwrap(), Dual::new(1.0, 0.0));
1053 }
1054
1055 #[test]
1056 fn test_partial_ord() {
1057 assert!(Dual::new(1.0, 2.0) < Dual::new(3.0, 4.0));
1059 assert!(Dual::new(1.0, 4.0) < Dual::new(3.0, 2.0));
1060 assert!(Dual::new(-3.0, -4.0) < Dual::new(-1.0, -2.0));
1061 assert!(Dual::new(-3.0, -2.0) < Dual::new(-1.0, -4.0));
1062
1063 assert!(Dual::new(3.0, 4.0) > Dual::new(1.0, 2.0));
1065 assert!(Dual::new(3.0, 2.0) > Dual::new(1.0, 4.0));
1066 assert!(Dual::new(-1.0, -2.0) > Dual::new(-3.0, -4.0));
1067 assert!(Dual::new(-1.0, -4.0) > Dual::new(-3.0, -2.0));
1068
1069 assert!(Dual::new(0.0, 2.0) <= Dual::new(1.0, 2.0));
1071 assert!(Dual::new(1.0, 2.0) <= Dual::new(1.0, 2.0));
1072
1073 assert!(Dual::new(2.0, 2.0) >= Dual::new(1.0, 2.0));
1075 assert!(Dual::new(1.0, 2.0) >= Dual::new(1.0, 2.0));
1076 }
1077
1078 #[test]
1079 fn test_neg() {
1080 assert_eq!(-Dual::new(1.0, 2.0), Dual::new(-1.0, -2.0));
1081 assert_eq!(-Dual::new(1.0, -2.0), Dual::new(-1.0, 2.0));
1082 assert_eq!(-Dual::new(-1.0, 2.0), Dual::new(1.0, -2.0));
1083 assert_eq!(-Dual::new(-1.0, -2.0), Dual::new(1.0, 2.0));
1084 }
1085
1086 #[test]
1087 fn test_nan() {
1088 let num = Dual::nan();
1089 assert!(num.get_real().is_nan());
1090 assert!(num.get_dual().is_nan());
1091 }
1092
1093 #[test]
1094 fn test_infinity() {
1095 let num = Dual::infinity();
1096 assert!(num.get_real().is_infinite() & (num.get_real() > 0.0));
1097 assert!(num.get_dual().is_infinite() & (num.get_dual() > 0.0));
1098 }
1099
1100 #[test]
1101 fn test_neg_infinity() {
1102 let num = Dual::neg_infinity();
1103 assert!(num.get_real().is_infinite() & (num.get_real() < 0.0));
1104 assert!(num.get_dual().is_infinite() & (num.get_dual() < 0.0));
1105 }
1106
1107 #[test]
1108 fn test_neg_zero() {
1109 let num = Dual::neg_zero();
1110 assert!(num.get_real().is_zero());
1111 assert!(num.get_dual().is_zero());
1112 }
1113
1114 #[test]
1115 fn test_min_value() {
1116 let num = Dual::min_value();
1117 assert!(num.get_real() == f64::MIN);
1118 assert!(num.get_dual() == f64::MIN);
1119 }
1120
1121 #[test]
1122 fn test_min_positive_value() {
1123 let num = Dual::min_positive_value();
1124 assert!(num.get_real() == f64::MIN_POSITIVE);
1125 assert!(num.get_dual() == f64::MIN_POSITIVE);
1126 }
1127
1128 #[test]
1129 fn test_max_value() {
1130 let num = Dual::max_value();
1131 assert!(num.get_real() == f64::MAX);
1132 assert!(num.get_dual() == f64::MAX);
1133 }
1134
1135 #[test]
1136 fn test_is_nan() {
1137 assert!(Dual::nan().is_nan());
1138 assert!(Dual::new(f64::NAN, 0.0).is_nan());
1139 assert!(!Dual::new(0.0, f64::NAN).is_nan());
1140 assert!(!Dual::new(0.0, 0.0).is_nan());
1141 }
1142
1143 #[test]
1144 fn test_is_infinite() {
1145 assert!(Dual::infinity().is_infinite());
1146 assert!(Dual::neg_infinity().is_infinite());
1147 assert!(Dual::new(f64::INFINITY, 0.0).is_infinite());
1148 assert!(Dual::new(f64::NEG_INFINITY, 0.0).is_infinite());
1149 assert!(!Dual::new(0.0, f64::INFINITY).is_infinite());
1150 assert!(!Dual::new(0.0, f64::NEG_INFINITY).is_infinite());
1151 assert!(!Dual::new(0.0, 0.0).is_infinite());
1152 }
1153
1154 #[test]
1155 fn test_is_finite() {
1156 assert!(!Dual::infinity().is_finite());
1157 assert!(!Dual::neg_infinity().is_finite());
1158 assert!(!Dual::new(f64::INFINITY, 0.0).is_finite());
1159 assert!(!Dual::new(f64::NEG_INFINITY, 0.0).is_finite());
1160 assert!(Dual::new(0.0, f64::INFINITY).is_finite());
1161 assert!(Dual::new(0.0, f64::NEG_INFINITY).is_finite());
1162 assert!(Dual::new(0.0, 0.0).is_finite());
1163 }
1164
1165 #[test]
1174 fn test_is_normal() {
1175 assert!(Dual::new(1.0, f64::NAN).is_normal());
1178 assert!(Dual::new(f64::MIN_POSITIVE, f64::NAN).is_normal());
1179 assert!(Dual::new(f64::MAX, f64::NAN).is_normal());
1180
1181 assert!(!Dual::new(0.0, 1.0).is_normal()); assert!(!Dual::new(f64::NAN, 1.0).is_normal()); assert!(!Dual::new(f64::INFINITY, 1.0).is_normal()); assert!(!Dual::new(f64::NEG_INFINITY, 1.0).is_normal()); assert!(!Dual::new(1.0e-308_f64, 1.0).is_normal()); }
1189
1190 #[test]
1191 fn test_classify() {
1192 assert_eq!(Dual::new(1.0, f64::NAN).classify(), FpCategory::Normal);
1195 assert_eq!(
1196 Dual::new(f64::MIN_POSITIVE, f64::NAN).classify(),
1197 FpCategory::Normal
1198 );
1199 assert_eq!(Dual::new(f64::MAX, f64::NAN).classify(), FpCategory::Normal);
1200
1201 assert_eq!(Dual::new(0.0, 1.0).classify(), FpCategory::Zero);
1204 assert_eq!(Dual::new(f64::NAN, 1.0).classify(), FpCategory::Nan);
1205 assert_eq!(
1206 Dual::new(f64::INFINITY, 1.0).classify(),
1207 FpCategory::Infinite
1208 );
1209 assert_eq!(
1210 Dual::new(f64::NEG_INFINITY, 1.0).classify(),
1211 FpCategory::Infinite
1212 );
1213 assert_eq!(
1214 Dual::new(1.0e-308_f64, 1.0).classify(),
1215 FpCategory::Subnormal
1216 );
1217 }
1218
1219 #[test]
1220 fn test_floor() {
1221 assert_eq!(Dual::new(2.7, 2.7).floor(), Dual::new(2.0, 0.0));
1222 assert_eq!(Dual::new(-2.7, -2.7).floor(), Dual::new(-3.0, 0.0));
1223 }
1224
1225 #[test]
1226 fn test_ceil() {
1227 assert_eq!(Dual::new(2.7, 2.7).ceil(), Dual::new(3.0, 0.0));
1228 assert_eq!(Dual::new(-2.7, -2.7).ceil(), Dual::new(-2.0, 0.0));
1229 }
1230
1231 #[test]
1232 fn test_round() {
1233 assert_eq!(Dual::new(2.3, 2.3).round(), Dual::new(2.0, 0.0));
1234 assert_eq!(Dual::new(2.7, 2.7).round(), Dual::new(3.0, 0.0));
1235 assert_eq!(Dual::new(-2.7, -2.7).round(), Dual::new(-3.0, 0.0));
1236 assert_eq!(Dual::new(-2.3, -2.3).round(), Dual::new(-2.0, 0.0));
1237 }
1238
1239 #[test]
1240 fn test_trunc() {
1241 assert_eq!(Dual::new(2.3, 2.3).trunc(), Dual::new(2.0, 0.0));
1242 assert_eq!(Dual::new(2.7, 2.7).trunc(), Dual::new(2.0, 0.0));
1243 assert_eq!(Dual::new(-2.7, -2.7).trunc(), Dual::new(-2.0, 0.0));
1244 assert_eq!(Dual::new(-2.3, -2.3).trunc(), Dual::new(-2.0, 0.0));
1245 }
1246
1247 #[test]
1248 fn test_fract() {
1249 assert_eq!(Dual::new(2.5, 2.5).fract(), Dual::new(0.5, 2.5));
1250 assert_eq!(Dual::new(-2.5, -2.5).fract(), Dual::new(-0.5, -2.5));
1251 }
1252
1253 #[test]
1254 fn test_abs() {
1255 assert_eq!(Dual::new(1.0, 2.0).abs(), Dual::new(1.0, 2.0));
1256 assert_eq!(Dual::new(-1.0, -2.0).abs(), Dual::new(1.0, 2.0));
1257 assert_eq!(Dual::new(-1.0, 2.0).abs(), Dual::new(1.0, -2.0));
1258 }
1259
1260 #[test]
1261 fn test_signum() {
1262 assert_eq!(Dual::new(2.0, 4.0).signum(), Dual::new(1.0, 0.0));
1263 assert_eq!(Dual::new(-2.0, -4.0).signum(), Dual::new(-1.0, 0.0));
1264 }
1265
1266 #[test]
1267 fn test_is_sign_positive() {
1268 assert!(Dual::new(2.0, -4.0).is_sign_positive());
1269 assert!(!Dual::new(-2.0, 4.0).is_sign_positive());
1270 }
1271
1272 #[test]
1273 fn test_is_sign_negative() {
1274 assert!(Dual::new(-2.0, 4.0).is_sign_negative());
1275 assert!(!Dual::new(2.0, -4.0).is_sign_negative());
1276 }
1277
1278 #[test]
1279 fn test_mul_add() {
1280 let a = Dual::new(1.0, 3.0);
1281 let b = Dual::new(-2.0, 5.0);
1282 let c = Dual::new(10.0, -4.0);
1283 assert_eq!(c.mul_add(a, b), (c * a) + b);
1284 }
1285
1286 #[test]
1287 fn test_recip() {
1288 assert_eq!(Dual::new(2.0, -5.0).recip(), Dual::new(0.5, 1.25));
1289 }
1290
1291 #[test]
1292 fn test_powi() {
1293 assert_eq!(Dual::new(2.0, -5.0).powi(0), Dual::new(1.0, 0.0));
1294 assert_eq!(Dual::new(2.0, -5.0).powi(1), Dual::new(2.0, -5.0));
1295 assert_eq!(Dual::new(2.0, -5.0).powi(2), Dual::new(4.0, -20.0));
1296 assert_eq!(Dual::new(2.0, -5.0).powi(3), Dual::new(8.0, -60.0));
1297 }
1298
1299 #[test]
1300 fn test_powf() {
1301 assert_eq!(
1303 Dual::new(2.0, -5.0).powf(Dual::new(0.0, 0.0)),
1304 Dual::new(2.0, -5.0).powi(0)
1305 );
1306 assert_eq!(
1307 Dual::new(2.0, -5.0).powf(Dual::new(1.0, 0.0)),
1308 Dual::new(2.0, -5.0).powi(1)
1309 );
1310 assert_eq!(
1311 Dual::new(2.0, -5.0).powf(Dual::new(2.0, 0.0)),
1312 Dual::new(2.0, -5.0).powi(2)
1313 );
1314 assert_equal_to_decimal!(
1315 Dual::new(2.0, -5.0).powf(Dual::new(3.0, 0.0)),
1316 Dual::new(2.0, -5.0).powi(3),
1317 14
1318 );
1319
1320 assert_equal_to_decimal!(
1322 Dual::new(2.0, -5.0).powf(Dual::new(0.5, 0.0)),
1323 Dual::new(2.0, -5.0).sqrt(),
1324 15
1325 );
1326
1327 assert_equal_to_decimal!(
1329 Dual::new(2.0, -5.0).powf(Dual::new(1.0 / 3.0, 0.0)),
1330 Dual::new(2.0, -5.0).cbrt(),
1331 15
1332 );
1333
1334 assert_eq!(
1336 Dual::new(2.0, -5.0).powf(Dual::new(-5.0, 4.0)),
1337 Dual::new(0.03125, 0.4772683975699932)
1338 );
1339 }
1340
1341 #[test]
1342 fn test_sqrt() {
1343 assert_eq!(Dual::new(4.0, 25.0).sqrt(), Dual::new(2.0, 6.25));
1344 }
1345
1346 #[test]
1347 fn test_exp() {
1348 assert_eq!(
1349 Dual::new(2.0, -3.0).exp(),
1350 Dual::new(2.0.exp(), -3.0 * 2.0.exp())
1351 );
1352 }
1353
1354 #[test]
1355 fn test_exp2() {
1356 assert_eq!(
1357 Dual::new(2.0, -3.0).exp2(),
1358 Dual::new(2.0.exp2(), -8.317766166719343)
1359 );
1360 }
1361
1362 #[test]
1363 fn test_ln() {
1364 assert_eq!(Dual::new(5.0, 8.0).ln(), Dual::new(5.0.ln(), 8.0 / 5.0));
1365 }
1366
1367 #[test]
1368 fn test_log() {
1369 assert_eq!(
1370 Dual::new(5.0, 8.0).log(Dual::new(4.5, 0.0)),
1371 Dual::new(5.0.log(4.5), 1.0637750447080176)
1372 );
1373 }
1374
1375 #[test]
1376 fn test_log2() {
1377 assert_eq!(
1378 Dual::new(5.0, 8.0).log2(),
1379 Dual::new(5.0.log2(), 2.3083120654223412)
1380 );
1381 }
1382
1383 #[test]
1384 fn test_log10() {
1385 assert_equal_to_decimal!(
1386 Dual::new(5.0, 8.0).log10(),
1387 Dual::new(5.0.log10(), 0.6948711710452028),
1388 16
1389 );
1390 }
1391
1392 #[test]
1393 fn test_max() {
1394 assert_eq!(
1395 Dual::new(1.0, 2.0).max(Dual::new(3.0, 4.0)),
1396 Dual::new(3.0, 4.0)
1397 );
1398 assert_eq!(
1399 Dual::new(3.0, 2.0).max(Dual::new(1.0, 4.0)),
1400 Dual::new(3.0, 2.0)
1401 );
1402 assert_eq!(
1403 Dual::new(3.0, 4.0).max(Dual::new(1.0, 2.0)),
1404 Dual::new(3.0, 4.0)
1405 );
1406 assert_eq!(
1407 Dual::new(-1.0, 2.0).max(Dual::new(-3.0, 4.0)),
1408 Dual::new(-1.0, 2.0)
1409 );
1410 }
1411
1412 #[test]
1413 fn test_min() {
1414 assert_eq!(
1415 Dual::new(1.0, 2.0).min(Dual::new(3.0, 4.0)),
1416 Dual::new(1.0, 2.0)
1417 );
1418 assert_eq!(
1419 Dual::new(3.0, 2.0).min(Dual::new(1.0, 4.0)),
1420 Dual::new(1.0, 4.0)
1421 );
1422 assert_eq!(
1423 Dual::new(3.0, 4.0).min(Dual::new(1.0, 2.0)),
1424 Dual::new(1.0, 2.0)
1425 );
1426 assert_eq!(
1427 Dual::new(-1.0, 2.0).min(Dual::new(-3.0, 4.0)),
1428 Dual::new(-3.0, 4.0)
1429 );
1430 }
1431
1432 #[test]
1433 fn test_abs_sub() {
1434 assert_eq!(
1435 Dual::new(4.0, 5.0).abs_sub(Dual::new(2.0, 8.0)),
1436 Dual::new(2.0, -3.0)
1437 );
1438 }
1439
1440 #[test]
1441 fn test_cbrt() {
1442 assert_eq!(Dual::new(8.0, 27.0).cbrt(), Dual::new(2.0, 2.25));
1443 }
1444
1445 #[test]
1446 fn test_hypot() {
1447 assert_eq!(
1449 Dual::new(1.0, 2.0).hypot(Dual::new(3.0, 4.0)),
1450 Dual::new(3.1622776601683795, 4.427188724235731)
1451 );
1452
1453 assert_eq!(
1455 Dual::new(1.0, 2.0).hypot(Dual::new(3.0, 4.0)),
1456 (Dual::new(1.0, 2.0).powi(2) + Dual::new(3.0, 4.0).powi(2)).sqrt()
1457 );
1458 }
1459
1460 #[test]
1461 fn test_sin() {
1462 assert_eq!(Dual::new(FRAC_PI_6, 2.0).sin(), Dual::new(0.5, 3.0.sqrt()));
1463 }
1464
1465 #[test]
1466 fn test_cos() {
1467 assert_eq!(
1468 Dual::new(FRAC_PI_6, 2.0).cos(),
1469 Dual::new(3.0.sqrt() / 2.0, -1.0)
1470 );
1471 }
1472
1473 #[test]
1474 fn test_tan() {
1475 assert_equal_to_decimal!(
1476 Dual::new(FRAC_PI_6, 2.0).tan(),
1477 Dual::new(3.0.sqrt() / 3.0, 8.0 / 3.0),
1478 15
1479 );
1480 }
1481
1482 #[test]
1483 fn test_asin() {
1484 assert_equal_to_decimal!(
1485 Dual::new(0.5, 3.0).asin(),
1486 Dual::new(FRAC_PI_6, 3.0 / 0.75.sqrt()),
1487 16
1488 );
1489 }
1490
1491 #[test]
1492 fn test_acos() {
1493 assert_equal_to_decimal!(
1494 Dual::new(3.0.sqrt() / 2.0, 3.0).acos(),
1495 Dual::new(FRAC_PI_6, -6.0),
1496 15
1497 );
1498 }
1499
1500 #[test]
1501 fn test_atan() {
1502 assert_eq!(Dual::new(1.0, 3.0).atan(), Dual::new(FRAC_PI_4, 1.5));
1503 }
1504
1505 #[test]
1506 fn test_atan2() {
1507 let x = Dual::new(3.0, 2.0);
1508 let y = Dual::new(-3.0, 5.0);
1509 let angle_expected = Dual::new(-FRAC_PI_4, 7.0 / 6.0);
1510 assert_eq!(y.atan2(x), angle_expected);
1511 }
1512
1513 #[test]
1514 fn test_sin_cos() {
1515 let (sin, cos) = Dual::new(FRAC_PI_6, 2.0).sin_cos();
1516 assert_eq!(sin, Dual::new(0.5, 3.0.sqrt()));
1517 assert_eq!(cos, Dual::new(3.0.sqrt() / 2.0, -1.0));
1518 }
1519
1520 #[test]
1521 fn test_exp_m1() {
1522 assert_eq!(
1523 Dual::new(3.0, 5.0).exp_m1(),
1524 Dual::new(3.0, 5.0).exp() - Dual::one()
1525 );
1526 }
1527
1528 #[test]
1529 fn test_ln_1p() {
1530 assert_eq!(
1531 Dual::new(3.0, 5.0).ln_1p(),
1532 (Dual::new(3.0, 5.0) + Dual::one()).ln()
1533 );
1534 }
1535
1536 #[test]
1537 fn test_sinh() {
1538 assert_equal_to_decimal!(
1539 Dual::new(1.0, 2.0).sinh(),
1540 Dual::new(((E * E) - 1.0) / (2.0 * E), ((E * E) + 1.0) / E),
1541 15
1542 );
1543 }
1544
1545 #[test]
1546 fn test_cosh() {
1547 assert_equal_to_decimal!(
1548 Dual::new(1.0, 2.0).cosh(),
1549 Dual::new(((E * E) + 1.0) / (2.0 * E), ((E * E) - 1.0) / E),
1550 15
1551 );
1552 }
1553
1554 #[test]
1555 fn test_tanh() {
1556 assert_equal_to_decimal!(
1557 Dual::new(1.0, 2.0).tanh(),
1558 Dual::new(
1559 (1.0 - E.powi(-2)) / (1.0 + E.powi(-2)),
1560 2.0 * ((2.0 * E) / (E.powi(2) + 1.0)).powi(2)
1561 ),
1562 15
1563 );
1564 }
1565
1566 #[test]
1567 fn test_asinh() {
1568 assert_eq!(Dual::new(1.0, 2.0).sinh().asinh(), Dual::new(1.0, 2.0));
1569 }
1570
1571 #[test]
1572 fn test_acosh() {
1573 assert_eq!(Dual::new(1.0, 2.0).cosh().acosh(), Dual::new(1.0, 2.0));
1574 }
1575
1576 #[test]
1577 fn test_atanh() {
1578 assert_equal_to_decimal!(Dual::new(1.0, 2.0).tanh().atanh(), Dual::new(1.0, 2.0), 16);
1579 }
1580
1581 #[test]
1582 fn test_integer_decode() {
1583 assert_eq!(
1584 Dual::new(1.2345e-5, 6.789e-7).integer_decode(),
1585 (1.2345e-5).integer_decode()
1586 );
1587 }
1588
1589 #[test]
1590 fn test_add_assign_dual_dual() {
1591 let mut a = Dual::new(1.0, 2.0);
1592 a += Dual::new(3.0, 4.0);
1593 assert_eq!(a, Dual::new(4.0, 6.0));
1594 }
1595
1596 #[test]
1597 fn test_sub_assign_dual_dual() {
1598 let mut a = Dual::new(1.0, 2.0);
1599 a -= Dual::new(4.0, 3.0);
1600 assert_eq!(a, Dual::new(-3.0, -1.0));
1601 }
1602
1603 #[test]
1604 fn test_mul_assign_dual_dual() {
1605 let mut a = Dual::new(1.0, 2.0);
1606 a *= Dual::new(3.0, -4.0);
1607 assert_eq!(a, Dual::new(3.0, 2.0));
1608 }
1609
1610 #[test]
1611 fn test_div_assign_dual_dual() {
1612 let mut a = Dual::new(1.0, 2.0);
1613 a /= Dual::new(3.0, 4.0);
1614 assert_eq!(a, Dual::new(1.0 / 3.0, 2.0 / 9.0));
1615 }
1616
1617 #[test]
1618 fn test_rem_assign_dual_dual() {
1619 let mut a = Dual::new(5.0, 2.0);
1620 let b = Dual::new(3.0, 4.0);
1621 a %= b;
1622 assert_eq!(a, Dual::new(2.0, -2.0));
1623 }
1624
1625 #[test]
1626 fn test_add_dual_f64() {
1627 assert_eq!(Dual::new(1.0, 2.0) + 3.0, Dual::new(4.0, 2.0));
1628 }
1629
1630 #[test]
1631 fn test_sub_dual_f64() {
1632 assert_eq!(Dual::new(1.0, 2.0) - 3.0, Dual::new(-2.0, 2.0));
1633 }
1634
1635 #[test]
1636 fn test_mul_dual_f64() {
1637 assert_eq!(Dual::new(1.0, -2.0) * 3.0, Dual::new(3.0, -6.0));
1638 }
1639
1640 #[test]
1641 fn test_div_dual_f64() {
1642 assert_eq!(Dual::new(1.0, 2.0) / 4.0, Dual::new(0.25, 0.5));
1643 }
1644
1645 #[test]
1646 fn test_rem_dual_f64() {
1647 assert_eq!(Dual::new(5.0, 1.0) % 3.0, Dual::new(2.0, 1.0));
1649
1650 let a = Dual::new(5.0, 1.0);
1653 let n = 3.0;
1654 assert_eq!(a % n, a - n * (a / n).trunc());
1655 }
1656
1657 #[test]
1658 fn test_add_assign_dual_f64() {
1659 let mut a = Dual::new(1.0, 2.0);
1660 a += 3.0;
1661 assert_eq!(a, Dual::new(4.0, 2.0));
1662 }
1663
1664 #[test]
1665 fn test_sub_assign_dual_f64() {
1666 let mut a = Dual::new(1.0, 2.0);
1667 a -= 3.0;
1668 assert_eq!(a, Dual::new(-2.0, 2.0));
1669 }
1670
1671 #[test]
1672 fn test_mul_assign_dual_f64() {
1673 let mut a = Dual::new(2.0, -3.0);
1674 a *= 5.0;
1675 assert_eq!(a, Dual::new(10.0, -15.0));
1676 }
1677
1678 #[test]
1679 fn test_div_assign_dual_f64() {
1680 let mut a = Dual::new(1.0, 2.0);
1681 a /= 4.0;
1682 assert_eq!(a, Dual::new(0.25, 0.5));
1683 }
1684
1685 #[test]
1686 fn test_rem_assign_dual_f64() {
1687 let mut a = Dual::new(5.0, 1.0);
1688 let n = 3.0;
1689 a %= n;
1690 assert_eq!(a, Dual::new(2.0, 1.0));
1691 }
1692
1693 #[test]
1694 fn test_add_f64_dual() {
1695 assert_eq!(1.0 + Dual::new(2.0, 3.0), Dual::new(3.0, 3.0));
1696 }
1697
1698 #[test]
1699 fn test_sub_f64_dual() {
1700 assert_eq!(1.0 - Dual::new(2.0, 3.0), Dual::new(-1.0, 3.0));
1701 }
1702
1703 #[test]
1704 fn test_mul_f64_dual() {
1705 assert_eq!(5.0 * Dual::new(2.0, -3.0), Dual::new(10.0, -15.0));
1706 }
1707
1708 #[test]
1709 fn test_div_f64_dual() {
1710 assert_eq!(5.0 / Dual::new(2.0, -3.0), Dual::new(2.5, 3.75));
1711 }
1712
1713 #[test]
1714 fn test_rem_f64_dual() {
1715 assert_eq!(5.0 % Dual::new(2.0, -3.0), Dual::new(1.0, 6.0));
1717
1718 assert_eq!(
1720 5.0 % Dual::new(2.0, -3.0),
1721 Dual::new(5.0, 0.0) % Dual::new(2.0, -3.0)
1722 );
1723 }
1724
1725 #[test]
1727 fn test_scalar() {
1728 fn add_scalar<S: Scalar>(x: S, y: S) -> S {
1729 x + y
1730 }
1731 assert_eq!(
1732 add_scalar(Dual::new(5.0, 4.0), Dual::new(3.0, 2.0)),
1733 Dual::new(8.0, 6.0)
1734 );
1735 }
1736}