1use crate::{
4 fbig::FBig,
5 repr::{Context, Repr},
6 round::{mode::Zero, Round},
7 utils::{digit_len, split_digits_ref},
8};
9use core::fmt::{self, Alignment, Display, Formatter, Write};
10use dashu_base::{Sign, UnsignedAbs};
11use dashu_int::{IBig, Word};
12
13trait DebugStructHelper {
14 fn field_significand<const B: Word>(&mut self, signif: &IBig) -> &mut Self;
16}
17
18impl<'a, 'b> DebugStructHelper for fmt::DebugStruct<'a, 'b> {
19 fn field_significand<const B: Word>(&mut self, signif: &IBig) -> &mut Self {
20 match B {
21 2 => self.field(
22 "significand",
23 &format_args!("{:?} ({} bits)", signif, digit_len::<B>(signif)),
24 ),
25 10 => self.field("significand", &format_args!("{:#?}", signif)),
26 _ => self.field(
27 "significand",
28 &format_args!("{:?} ({} digits)", signif, digit_len::<B>(signif)),
29 ),
30 }
31 }
32}
33
34impl<const B: Word> fmt::Debug for Repr<B> {
35 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36 if self.is_infinite() {
38 return match self.sign() {
39 Sign::Positive => f.write_str("inf"),
40 Sign::Negative => f.write_str("-inf"),
41 };
42 }
43
44 if f.alternate() {
45 f.debug_struct("Repr")
46 .field_significand::<B>(&self.significand)
47 .field("exponent", &format_args!("{} ^ {}", &B, &self.exponent))
48 .finish()
49 } else {
50 f.write_fmt(format_args!("{:?} * {} ^ {}", &self.significand, &B, &self.exponent))
51 }
52 }
53}
54
55impl<R: Round> fmt::Debug for Context<R> {
56 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
57 let rnd_name = core::any::type_name::<R>();
58 let rnd_name = rnd_name
59 .rfind("::")
60 .map(|pos| &rnd_name[pos + 2..])
61 .unwrap_or(rnd_name);
62 f.debug_struct("Context")
63 .field("precision", &self.precision)
64 .field("rounding", &format_args!("{}", rnd_name))
65 .finish()
66 }
67}
68
69impl<const B: Word> Repr<B> {
70 fn fmt_round<R: Round>(&self, f: &mut Formatter<'_>) -> fmt::Result {
73 if self.is_infinite() {
75 return match self.sign() {
76 Sign::Positive => f.write_str("inf"),
77 Sign::Negative => f.write_str("-inf"),
78 };
79 }
80
81 let negative = self.significand.sign() == Sign::Negative;
83 let rounded_signif;
84 let (signif, exp) = if let Some(prec) = f.precision() {
85 let diff = prec as isize + self.exponent;
86 if diff < 0 {
87 let shift = -diff as usize;
88 let (signif, rem) = split_digits_ref::<B>(&self.significand, shift);
89 let adjust = R::round_fract::<B>(&signif, rem, shift);
90 rounded_signif = signif + adjust;
91 (&rounded_signif, self.exponent - diff)
92 } else {
93 (&self.significand, self.exponent)
94 }
95 } else {
96 (&self.significand, self.exponent)
97 };
98
99 let (left_pad, right_pad) = if let Some(min_width) = f.width() {
101 let mut signif_digits = digit_len::<B>(signif);
104 let leading_zeros = -(exp + signif_digits as isize - 1).min(0) as usize;
106 let mut trailing_zeros = exp.max(0) as usize;
108
109 if let Some(prec) = f.precision() {
111 let diff = prec as isize + exp.min(0);
112 if diff > 0 {
113 trailing_zeros += diff as usize;
114 }
115 }
116 if leading_zeros == 0 {
117 signif_digits = signif_digits.max(1);
119 }
120
121 let has_sign = (negative || f.sign_plus()) as usize;
122 let has_float_point = if exp > 0 {
123 f.precision().unwrap_or(0) > 0
126 } else {
127 f.precision() != Some(0) } as usize;
131
132 let width = signif_digits + has_sign + has_float_point + leading_zeros + trailing_zeros;
133
134 if width >= min_width {
136 (0, 0)
137 } else if f.sign_aware_zero_pad() {
138 (min_width - width, 0)
139 } else {
140 match f.align() {
141 Some(Alignment::Left) => (0, min_width - width),
142 Some(Alignment::Right) | None => (min_width - width, 0),
143 Some(Alignment::Center) => {
144 let diff = min_width - width;
145 (diff / 2, diff - diff / 2)
146 }
147 }
148 }
149 } else {
150 (0, 0)
151 };
152
153 let fill = if f.sign_aware_zero_pad() {
155 '0'
156 } else {
157 f.fill()
158 };
159 for _ in 0..left_pad {
160 f.write_char(fill)?;
161 }
162
163 if exp < 0 {
165 let exp = -exp as usize;
167 let (int, fract) = split_digits_ref::<B>(signif, exp);
168
169 let frac_digits = digit_len::<B>(&fract);
170 debug_assert!(frac_digits <= exp);
171
172 if !negative && f.sign_plus() {
174 f.write_char('+')?;
175 }
176 if int.is_zero() {
177 if negative {
178 f.write_char('-')?;
179 }
180 f.write_char('0')?;
181 } else {
182 f.write_fmt(format_args!("{}", int.in_radix(B as u32)))?;
183 }
184
185 let fract = fract.unsigned_abs(); if let Some(prec) = f.precision() {
188 if prec != 0 {
190 f.write_char('.')?;
191 if exp >= prec {
192 debug_assert!(exp == prec);
194
195 if prec > frac_digits {
197 for _ in 0..prec - frac_digits {
198 f.write_char('0')?;
199 }
200 }
201 if frac_digits > 0 {
202 f.write_fmt(format_args!("{}", fract.in_radix(B as u32)))?;
203 }
204 } else {
205 for _ in 0..exp - frac_digits {
207 f.write_char('0')?;
208 }
209 f.write_fmt(format_args!("{}", fract.in_radix(B as u32)))?;
210 for _ in 0..prec - exp {
211 f.write_char('0')?;
212 }
213 }
214 }
215 } else if frac_digits > 0 {
216 f.write_char('.')?;
217 for _ in 0..(exp - frac_digits) {
218 f.write_char('0')?;
219 }
220 f.write_fmt(format_args!("{}", fract.in_radix(B as u32)))?;
221 }
222 } else {
223 if !negative && f.sign_plus() {
228 f.write_char('+')?;
229 }
230 if signif.is_zero() {
231 if negative {
232 f.write_char('-')?;
233 }
234 f.write_char('0')?;
235 } else {
236 f.write_fmt(format_args!("{}", signif.in_radix(B as u32)))?;
237 }
238
239 for _ in 0..exp {
241 f.write_char('0')?;
242 }
243
244 if let Some(prec) = f.precision() {
246 if prec > 0 {
247 f.write_char('.')?;
248 for _ in 0..prec {
249 f.write_char('0')?;
250 }
251 }
252 }
253 };
254
255 for _ in 0..right_pad {
257 f.write_char(f.fill())?;
258 }
259
260 Ok(())
261 }
262}
263
264impl<const B: Word> Display for Repr<B> {
265 #[inline]
266 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
267 self.fmt_round::<Zero>(f)
268 }
269}
270
271impl<R: Round, const B: Word> fmt::Debug for FBig<R, B> {
272 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
273 if self.repr.is_infinite() {
275 return match self.repr.sign() {
276 Sign::Positive => f.write_str("inf"),
277 Sign::Negative => f.write_str("-inf"),
278 };
279 }
280
281 let rnd_name = core::any::type_name::<R>();
282 let rnd_name = rnd_name
283 .rfind("::")
284 .map(|pos| &rnd_name[pos + 2..])
285 .unwrap_or(rnd_name);
286
287 if f.alternate() {
288 f.debug_struct("FBig")
289 .field_significand::<B>(&self.repr.significand)
290 .field("exponent", &format_args!("{} ^ {}", &B, &self.repr.exponent))
291 .field("precision", &self.context.precision)
292 .field("rounding", &format_args!("{}", rnd_name))
293 .finish()
294 } else {
295 f.write_fmt(format_args!("{:?} (prec: {})", &self.repr, &self.context.precision))
296 }
297 }
298}
299
300impl<R: Round, const B: Word> Display for FBig<R, B> {
301 #[inline]
302 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
303 self.repr.fmt_round::<R>(f)
304 }
305}