oxinum_complex/native/core_traits.rs
1//! Core trait implementations for native [`BigComplex`]: [`Display`] and
2//! [`Debug`].
3//!
4//! [`PartialEq`] lives next to the arithmetic operators in
5//! [`super::complex_ops`]; `Eq`, `Ord`, and `Hash` are intentionally absent
6//! (see the [`super`] module docs — `BigFloat` is neither `Eq` nor `Hash`
7//! because of NaN, and the complex field has no ring-compatible order).
8//!
9//! # `Display`
10//!
11//! Renders as `<re> + <|im|>i` or `<re> - <|im|>i`, choosing the sign from
12//! [`BigFloat::is_sign_negative`] on the imaginary part and printing each
13//! component through `BigFloat`'s own `Display` (the exact `0xb…p…`
14//! hex-float form). The imaginary magnitude uses `im.abs()` so the chosen
15//! `+`/`-` separator is never duplicated by the component's own sign.
16
17use core::fmt;
18
19use super::BigComplex;
20
21impl fmt::Display for BigComplex {
22 /// Format as `a + bi` (or `a - bi` when the imaginary part is negative).
23 ///
24 /// Each component is delegated to [`BigFloat`](oxinum_float::native::BigFloat)'s
25 /// `Display`. The real part keeps its own sign; the imaginary part is shown
26 /// as a magnitude with an explicit `+`/`-` separator chosen from its sign.
27 ///
28 /// # Examples
29 ///
30 /// ```
31 /// use oxinum_complex::native::BigComplex;
32 /// let z = BigComplex::from_f64(1.0, -2.0, 53).expect("finite");
33 /// let s = format!("{z}");
34 /// assert!(s.contains('-'));
35 /// assert!(s.ends_with('i'));
36 /// ```
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 if self.im.is_sign_negative() {
39 // a - |b|i
40 write!(f, "{} - {}i", self.re, self.im.abs())
41 } else {
42 // a + bi (covers non-negative im, including the canonical zero)
43 write!(f, "{} + {}i", self.re, self.im)
44 }
45 }
46}
47
48impl fmt::Debug for BigComplex {
49 /// Structural debug view exposing the real and imaginary [`BigFloat`]s.
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 f.debug_struct("BigComplex")
52 .field("re", &self.re)
53 .field("im", &self.im)
54 .finish()
55 }
56}
57
58// ---------------------------------------------------------------------------
59// Tests
60// ---------------------------------------------------------------------------
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65
66 #[test]
67 fn display_positive_imag() {
68 let z = BigComplex::from_f64(1.0, 2.0, 53).expect("finite");
69 let s = format!("{z}");
70 assert!(s.contains(" + "), "expected ' + ' in {s:?}");
71 assert!(s.ends_with('i'), "expected trailing 'i' in {s:?}");
72 }
73
74 #[test]
75 fn display_negative_imag() {
76 let z = BigComplex::from_f64(1.0, -2.0, 53).expect("finite");
77 let s = format!("{z}");
78 assert!(s.contains(" - "), "expected ' - ' in {s:?}");
79 // The imaginary magnitude must not carry its own leading '-'.
80 assert!(!s.contains("- -"), "double sign in {s:?}");
81 assert!(s.ends_with('i'), "expected trailing 'i' in {s:?}");
82 }
83
84 #[test]
85 fn debug_mentions_fields() {
86 let z = BigComplex::from_f64(1.0, 2.0, 53).expect("finite");
87 let s = format!("{z:?}");
88 assert!(s.contains("BigComplex"), "{s:?}");
89 assert!(s.contains("re"), "{s:?}");
90 assert!(s.contains("im"), "{s:?}");
91 }
92}