dashu_cmplx/third_party/
num_complex.rs1use crate::cbig::CBig;
11use dashu_base::ConversionError;
12use dashu_float::round::Round;
13use dashu_float::FBig;
14use num_complex_v04::{Complex32, Complex64};
15
16macro_rules! impl_complex_conversions {
17 ($cx:ty, $f:ty) => {
18 impl<R: Round> TryFrom<$cx> for CBig<R, 2> {
19 type Error = ConversionError;
20
21 #[inline]
25 fn try_from(c: $cx) -> Result<Self, Self::Error> {
26 let re = FBig::try_from(c.re)?;
27 let im = FBig::try_from(c.im)?;
28 Ok(CBig::from_parts(re, im))
29 }
30 }
31
32 impl<R: Round> TryFrom<CBig<R, 2>> for $cx {
33 type Error = ConversionError;
34
35 #[inline]
39 fn try_from(z: CBig<R, 2>) -> Result<Self, Self::Error> {
40 let fctx = z.context.float();
41 let re = <$f>::try_from(FBig::from_repr(z.re, fctx))?;
42 let im = <$f>::try_from(FBig::from_repr(z.im, fctx))?;
43 Ok(<$cx>::new(re, im))
44 }
45 }
46 };
47}
48
49impl_complex_conversions!(Complex32, f32);
50impl_complex_conversions!(Complex64, f64);
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55 use dashu_float::round::mode;
56
57 type C2 = CBig<mode::Zero, 2>;
58
59 #[test]
60 fn f64_roundtrip() {
61 for (re, im) in [
62 (3.0_f64, 4.0),
63 (1.0, 0.0),
64 (0.0, 1.0),
65 (-2.0, 0.5),
66 (0.0, 0.0),
67 (1.5, -2.25),
68 ] {
69 let c = Complex64::new(re, im);
70 let z = C2::try_from(c).unwrap();
71 let back: Complex64 = z.try_into().unwrap();
72 assert_eq!(back, c, "roundtrip failed for {re}+{im}i");
73 }
74 }
75
76 #[test]
77 fn f32_roundtrip() {
78 for (re, im) in [(3.0_f32, 4.0), (-1.5_f32, 0.25)] {
79 let c = Complex32::new(re, im);
80 let z = C2::try_from(c).unwrap();
81 let back: Complex32 = z.try_into().unwrap();
82 assert_eq!(back, c);
83 }
84 }
85
86 #[test]
87 fn nan_is_out_of_bounds() {
88 assert_eq!(C2::try_from(Complex64::new(f64::NAN, 0.0)), Err(ConversionError::OutOfBounds));
89 assert_eq!(C2::try_from(Complex64::new(0.0, f64::NAN)), Err(ConversionError::OutOfBounds));
90 }
91
92 #[test]
93 fn infinities_preserved_on_lift() {
94 let z = C2::try_from(Complex64::new(f64::INFINITY, f64::NEG_INFINITY)).unwrap();
95 assert!(z.re().is_infinite());
96 assert!(z.im().is_infinite());
97 assert_eq!(Complex64::try_from(z), Err(ConversionError::LossOfPrecision));
99 }
100
101 #[test]
102 fn signed_zero_preserved() {
103 let z = C2::try_from(Complex64::new(-0.0, 0.0)).unwrap();
104 assert!(z.re().is_neg_zero());
105 assert!(z.im().is_pos_zero());
106 }
107
108 #[test]
109 fn high_precision_rounds_inexactly() {
110 let big = FBig::<mode::Zero, 2>::from_parts(((1u64 << 53) + 1).into(), 0);
112 let z = C2::from_parts(big, FBig::from(0));
113 assert_eq!(Complex64::try_from(z), Err(ConversionError::LossOfPrecision));
114 }
115}