Skip to main content

factorion_lib/
calculation_results.rs

1//! This module handles the formatting of the calculations (`The factorial of Subfactorial of 5 is`, etc.)
2
3#[cfg(any(feature = "serde", test))]
4use serde::{Deserialize, Serialize};
5
6use crate::rug::float::OrdFloat;
7use crate::rug::ops::{NegAssign, NotAssign, Pow};
8use crate::rug::{Float, Integer};
9use crate::{Consts, locale};
10use std::borrow::Cow;
11use std::fmt;
12use std::fmt::Write;
13
14pub mod recommended {
15    pub const NUMBER_DECIMALS_SCIENTIFIC: usize = 30;
16}
17
18impl fmt::Debug for CalculationResult {
19    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20        fn truncate<T: fmt::Debug>(val: &T) -> String {
21            let s = format!("{val:?}");
22            if s.len() > 25 {
23                format!("{}...", &s[..20])
24            } else {
25                s
26            }
27        }
28
29        match self {
30            CalculationResult::Exact(n) => write!(f, "Exact({})", truncate(n)),
31            CalculationResult::Approximate(of, int) => {
32                write!(
33                    f,
34                    "Approximate({}, {})",
35                    truncate(&of.as_float()),
36                    truncate(int)
37                )
38            }
39            CalculationResult::ApproximateDigits(i, n) => {
40                write!(f, "ApproximateDigits({}, {})", i, truncate(n))
41            }
42            CalculationResult::ApproximateDigitsTower(i, b, u, n) => {
43                write!(
44                    f,
45                    "ApproximateDigitsTower({}, {}, {}, {})",
46                    i,
47                    b,
48                    u,
49                    truncate(n)
50                )
51            }
52            CalculationResult::Float(of) => write!(f, "Float({})", truncate(&of.as_float())),
53            CalculationResult::ComplexInfinity => write!(f, "ComplexInfinity"),
54        }
55    }
56}
57
58/// The result of a calculation in various formats.
59#[derive(Clone, PartialEq, Ord, Eq, Hash, PartialOrd)]
60#[cfg_attr(any(feature = "serde", test), derive(Serialize, Deserialize))]
61pub enum CalculationResult {
62    Exact(Integer),
63    /// a * 10^b
64    Approximate(OrdFloat, Integer),
65    /// b digits (a is whether the number is negative)
66    ApproximateDigits(bool, Integer),
67    /// (^(c)10)^d digits (a is whether is negative, b is negative number of digits (super small))
68    ApproximateDigitsTower(bool, bool, Integer, Integer),
69    Float(OrdFloat),
70    ComplexInfinity,
71}
72
73/// A number in various formats. An alias of [CalculationResult].
74pub type Number = CalculationResult;
75
76impl Number {
77    pub fn negate(&mut self) {
78        match self {
79            Self::Approximate(x, _) | Self::Float(x) => x.as_float_mut().neg_assign(),
80            Self::Exact(n) => n.neg_assign(),
81            Self::ApproximateDigitsTower(n, _, _, _) | Self::ApproximateDigits(n, _) => {
82                n.not_assign()
83            }
84            Self::ComplexInfinity => {}
85        }
86    }
87    pub fn is_too_long(&self, too_big_number: &Integer) -> bool {
88        let n = match self {
89            CalculationResult::Exact(n)
90            | CalculationResult::ApproximateDigits(_, n)
91            | CalculationResult::Approximate(_, n)
92            | CalculationResult::ApproximateDigitsTower(_, _, _, n) => n,
93            CalculationResult::Float(_) | CalculationResult::ComplexInfinity => return false,
94        };
95        n > too_big_number
96    }
97}
98impl From<Integer> for Number {
99    fn from(value: Integer) -> Self {
100        Number::Exact(value)
101    }
102}
103impl From<i32> for Number {
104    fn from(value: i32) -> Self {
105        Number::Exact(value.into())
106    }
107}
108impl From<Float> for Number {
109    fn from(value: Float) -> Self {
110        Number::Float(value.into())
111    }
112}
113
114impl CalculationResult {
115    /// Formats a number. \
116    /// Shorten turns integers into scientific notation if that makes them shorter. \
117    /// Aggressive enables tertation for towers.
118    fn format(
119        &self,
120        acc: &mut String,
121        rough: &mut bool,
122        shorten: bool,
123        agressive: bool,
124        is_value: bool,
125        consts: &Consts,
126        locale: &locale::NumFormat,
127    ) -> std::fmt::Result {
128        let mut start = acc.len();
129        match &self {
130            CalculationResult::Exact(factorial) => {
131                if shorten {
132                    let (s, r) = truncate(factorial, consts);
133                    *rough = r;
134                    acc.write_str(&s)?;
135                } else {
136                    write!(acc, "{factorial}")?;
137                }
138            }
139            CalculationResult::Approximate(base, exponent) => {
140                let base = base.as_float();
141                format_float(acc, base, consts)?;
142                acc.write_str(" × 10^")?;
143                if shorten {
144                    acc.write_str("(")?;
145                    acc.write_str(&truncate(exponent, consts).0)?;
146                    acc.write_str(")")?;
147                } else {
148                    write!(acc, "{exponent}")?;
149                }
150            }
151            CalculationResult::ApproximateDigits(_, digits) => {
152                if is_value {
153                    acc.write_str("10^(")?;
154                }
155                if shorten {
156                    acc.write_str(&truncate(digits, consts).0)?;
157                } else {
158                    write!(acc, "{digits}")?;
159                }
160                if is_value {
161                    acc.write_str(")")?;
162                }
163            }
164            CalculationResult::ApproximateDigitsTower(_, negative, depth, exponent) => {
165                let depth = if is_value {
166                    depth.clone() + 1
167                } else {
168                    depth.clone()
169                };
170                acc.write_str(if *negative { "-" } else { "" })?;
171                // If we have a one on top, we gain no information by printing the whole tower.
172                // If depth is one, it is nicer to write 10¹ than ¹10.
173                if !agressive && depth <= usize::MAX && (depth <= 1 || exponent != &1) {
174                    if depth > 0 {
175                        acc.write_str("10^(")?;
176                    }
177                    if depth > 1 {
178                        // PANIC: We just checked, that it is <= usize::MAX and > 1 (implies >= 0), so it fits in usize
179                        acc.write_str(&"10\\^".repeat(depth.to_usize().unwrap() - 1))?;
180                        acc.write_str("(")?;
181                    }
182                    if shorten {
183                        acc.write_str(&truncate(exponent, consts).0)?;
184                    } else {
185                        write!(acc, "{exponent}")?;
186                    }
187                    if depth > 1 {
188                        acc.write_str("\\)")?;
189                    }
190                    if depth > 0 {
191                        acc.write_str(")")?;
192                    }
193                } else {
194                    let mut extra = 0;
195                    let mut exponent = Float::with_val(consts.float_precision, exponent);
196                    while exponent >= 10 {
197                        extra += 1;
198                        exponent = exponent.log10();
199                    }
200                    acc.write_str("^(")?;
201                    write!(acc, "{}", depth + extra)?;
202                    acc.write_str(")10")?;
203                }
204            }
205            CalculationResult::Float(gamma) => {
206                let gamma = gamma.as_float();
207                format_float(acc, gamma, consts)?;
208            }
209            CalculationResult::ComplexInfinity => {
210                acc.write_str("∞\u{0303}")?;
211            }
212        }
213        if *locale.decimal() != '.' {
214            let decimal = locale.decimal().to_string();
215            while start < acc.len() {
216                start = replace(acc, start, ".", &decimal);
217            }
218        }
219        Ok(())
220    }
221}
222
223#[derive(Debug, Clone, PartialEq, Ord, Eq, Hash, PartialOrd)]
224#[cfg_attr(any(feature = "serde", test), derive(Serialize, Deserialize))]
225pub struct Calculation {
226    /// The base number
227    pub value: Number,
228    /// Steps taken during calculation (level, negation)
229    pub steps: Vec<(i32, bool)>,
230    pub result: CalculationResult,
231}
232
233impl Calculation {
234    pub fn is_digit_tower(&self) -> bool {
235        matches!(
236            self,
237            Calculation {
238                result: CalculationResult::ApproximateDigitsTower(_, _, _, _),
239                ..
240            }
241        )
242    }
243    pub fn is_aproximate_digits(&self) -> bool {
244        matches!(
245            self,
246            Calculation {
247                result: CalculationResult::ApproximateDigits(_, _),
248                ..
249            }
250        )
251    }
252    pub fn is_approximate(&self) -> bool {
253        matches!(
254            self,
255            Calculation {
256                result: CalculationResult::Approximate(_, _),
257                ..
258            }
259        )
260    }
261    pub fn is_rounded(&self) -> bool {
262        matches!(
263            self,
264            Calculation {
265                value: Number::Float(_),
266                ..
267            }
268        ) && !matches!(
269            self,
270            Calculation {
271                result: CalculationResult::Float(_),
272                ..
273            }
274        )
275    }
276    pub fn is_too_long(&self, too_big_number: &Integer) -> bool {
277        self.result.is_too_long(too_big_number) || self.value.is_too_long(too_big_number)
278    }
279}
280
281impl Calculation {
282    /// Formats a Calcucation. \
283    /// Force shorten shortens all integers, if that makes them smaller. \
284    /// Agressive shorten replaces the description of what steps were taken with "All that of" and truns towers into tetration. \
285    /// Too big number is from when the integer part automatically gets shortened.
286    pub fn format(
287        &self,
288        acc: &mut String,
289        force_shorten: bool,
290        agressive_shorten: bool,
291        too_big_number: &Integer,
292        consts: &Consts,
293        locale: &locale::Format<'_>,
294    ) -> Result<(), std::fmt::Error> {
295        let frame_start = acc.len();
296        acc.write_str(
297            match (
298                &self.value,
299                &self.result,
300                agressive_shorten && self.steps.len() > 1,
301            ) {
302                // All that
303                (_, _, true) => locale.all_that(),
304                // on the order
305                (_, CalculationResult::ApproximateDigitsTower(_, _, _, _), _) => locale.order(),
306                // digits
307                (_, CalculationResult::ApproximateDigits(_, _), _) => locale.digits(),
308                // approximately
309                (Number::Float(_), _, _) | (_, CalculationResult::Approximate(_, _), _) => {
310                    locale.approx()
311                }
312                // is
313                _ => locale.exact(),
314            },
315        )?;
316        acc.write_str(" \n\n")?;
317
318        let mut number = String::new();
319        let mut rough = false;
320        self.value.format(
321            &mut number,
322            &mut rough,
323            force_shorten || self.result.is_too_long(too_big_number) || agressive_shorten,
324            agressive_shorten,
325            true,
326            consts,
327            &locale.number_format(),
328        )?;
329        if rough {
330            replace(acc, frame_start, "{number}", locale.rough_number());
331        }
332        replace(acc, frame_start, "{number}", &number);
333        replace(acc, frame_start, "{result}", "{number}");
334        let mut number = String::new();
335        let mut rough = false;
336        self.result.format(
337            &mut number,
338            &mut rough,
339            force_shorten || self.result.is_too_long(too_big_number) || agressive_shorten,
340            agressive_shorten,
341            false,
342            consts,
343            &locale.number_format(),
344        )?;
345        if rough {
346            replace(acc, frame_start, "{number}", locale.rough_number());
347        }
348        replace(acc, frame_start, "{number}", &number);
349
350        let len = self.steps.len();
351        let mut start = frame_start;
352        for (i, (level, neg)) in self.steps.iter().copied().rev().enumerate() {
353            if i != len - 1 {
354                replace(acc, start, "{factorial}", locale.nest());
355            }
356
357            if neg {
358                replace(acc, start, "{factorial}", "negative {factorial}");
359            }
360
361            let calc_start = replace(
362                acc,
363                start,
364                "{factorial}",
365                &Self::get_factorial_level_string(level.abs(), locale),
366            );
367
368            replace(
369                acc,
370                start,
371                "{factorial}",
372                if level < 0 {
373                    locale.termial()
374                } else {
375                    locale.factorial()
376                },
377            );
378            if *locale.capitalize_calc() {
379                let mut ind = acc[calc_start..].char_indices();
380                if let Some((start, _)) = ind.next()
381                    && let Some((end, _)) = ind.next()
382                {
383                    acc[calc_start..][start..end].make_ascii_uppercase();
384                }
385            }
386
387            if i != len - 1 {
388                start = replace(acc, start, "{next}", "{factorial}");
389            }
390        }
391        let mut ind = acc[frame_start..].char_indices();
392        if let Some((start, _)) = ind.next()
393            && let Some((end, _)) = ind.next()
394        {
395            acc[frame_start..][start..end].make_ascii_uppercase();
396        }
397
398        Ok(())
399    }
400
401    fn get_factorial_level_string<'a>(level: i32, locale: &'a locale::Format<'a>) -> Cow<'a, str> {
402        const SINGLES: [&str; 10] = [
403            "", "un", "duo", "tre", "quattuor", "quin", "sex", "septen", "octo", "novem",
404        ];
405        const SINGLES_LAST: [&str; 10] = [
406            "", "un", "du", "tr", "quadr", "quint", "sext", "sept", "oct", "non",
407        ];
408        const TENS: [&str; 10] = [
409            "",
410            "dec",
411            "vigin",
412            "trigin",
413            "quadragin",
414            "quinquagin",
415            "sexagin",
416            "septuagin",
417            "octogin",
418            "nonagin",
419        ];
420        const HUNDREDS: [&str; 10] = [
421            "",
422            "cen",
423            "ducen",
424            // Note this differs from the wikipedia list to disambiguate from 103, which continuing the pattern should be trecentuple
425            "tricen",
426            "quadringen",
427            "quingen",
428            "sescen",
429            "septingen",
430            "octingen",
431            "nongen",
432        ];
433        // Note that other than milluple, these are not found in a list, but continue the pattern from mill with different starts
434        const THOUSANDS: [&str; 10] = [
435            "", "mill", "bill", "trill", "quadrill", "quintill", "sextill", "septill", "octill",
436            "nonill",
437        ];
438        const BINDING_T: [[bool; 10]; 4] = [
439            // Singles
440            [
441                false, false, false, false, false, false, false, false, false, false,
442            ],
443            // Tens
444            [false, false, true, true, true, true, true, true, true, true],
445            // Hundreds
446            [false, true, true, true, true, true, true, true, true, true],
447            // Thousands
448            [
449                false, false, false, false, false, false, false, false, false, false,
450            ],
451        ];
452        if let Some(s) = locale.num_overrides().get(&level) {
453            return s.as_ref().into();
454        }
455        match level {
456            0 => locale.sub().as_ref().into(),
457            1 => "{factorial}".into(),
458            ..=9999 if !locale.force_num() => {
459                let singles = if level < 10 { SINGLES_LAST } else { SINGLES };
460                let mut acc = String::new();
461                let mut n = level;
462                let s = n % 10;
463                n /= 10;
464                acc.write_str(singles[s as usize]).unwrap();
465                let t = n % 10;
466                n /= 10;
467                acc.write_str(TENS[t as usize]).unwrap();
468                let h = n % 10;
469                n /= 10;
470                acc.write_str(HUNDREDS[h as usize]).unwrap();
471                let th = n % 10;
472                acc.write_str(THOUSANDS[th as usize]).unwrap();
473                // Check if we need tuple not uple
474                let last_written = [s, t, h, th]
475                    .iter()
476                    .cloned()
477                    .enumerate()
478                    .rev()
479                    .find(|(_, n)| *n != 0)
480                    .unwrap();
481                if BINDING_T[last_written.0][last_written.1 as usize] {
482                    acc.write_str("t").unwrap();
483                }
484                acc.write_str(locale.uple()).unwrap();
485
486                acc.into()
487            }
488            _ => {
489                let mut suffix = String::new();
490                write!(&mut suffix, "{level}-{{factorial}}").unwrap();
491                suffix.into()
492            }
493        }
494    }
495}
496/// Rounds a base 10 number string. \
497/// Uses the last digit to decide the rounding direction. \
498/// Rounds over 9s. This does **not** keep the length or turn rounded over digits into zeros. \
499/// If the input is all 9s, this will round to 10. \
500/// Stops when a decimal period is encountered, removing it.
501///
502/// Returns whether it overflowed.
503///
504/// # Panic
505/// This function may panic if less than two digits are supplied, or if it contains a non-digit of base 10, that is not a period.
506fn round(number: &mut String) -> bool {
507    // Check additional digit if we need to round
508    if let Some(digit) = number
509        .pop()
510        .map(|n| n.to_digit(10).expect("Not a base 10 number"))
511        && digit >= 5
512    {
513        let mut last_digit = number
514            .pop()
515            .and_then(|n| n.to_digit(10))
516            .expect("Not a base 10 number");
517        // Carry over at 9s
518        while last_digit == 9 {
519            let Some(digit) = number.pop() else {
520                // If we reached the end we get 10
521                number.push_str("10");
522                return true;
523            };
524            // Stop at decimal
525            if digit == '.' {
526                break;
527            }
528            let digit = digit.to_digit(10).expect("Not a base 10 number");
529            last_digit = digit;
530        }
531        // Round up
532        let _ = write!(number, "{}", last_digit + 1);
533    }
534    false
535}
536fn truncate(number: &Integer, consts: &Consts) -> (String, bool) {
537    let prec = consts.float_precision;
538    if number == &0 {
539        return (number.to_string(), false);
540    }
541    let negative = number.is_negative();
542    let orig_number = number;
543    let number = number.clone().abs();
544    let length = (Float::with_val(prec, &number).ln() / Float::with_val(prec, 10).ln())
545        .to_integer_round(crate::rug::float::Round::Down)
546        .unwrap()
547        .0;
548    let truncated_number: Integer = &number
549        / (Float::with_val(prec, 10)
550            .pow((length.clone() - consts.number_decimals_scientific - 1u8).max(Integer::ZERO))
551            .to_integer()
552            .unwrap());
553    let mut truncated_number = truncated_number.to_string();
554    if truncated_number.len() > consts.number_decimals_scientific {
555        round(&mut truncated_number);
556    }
557    if let Some(mut digit) = truncated_number.pop() {
558        while digit == '0' {
559            digit = match truncated_number.pop() {
560                Some(x) => x,
561                None => break,
562            }
563        }
564        truncated_number.push(digit);
565    }
566    // Only add decimal if we have more than one digit
567    if truncated_number.len() > 1 {
568        truncated_number.insert(1, '.'); // Decimal point
569    }
570    if negative {
571        truncated_number.insert(0, '-');
572    }
573    if length > consts.number_decimals_scientific + 1 {
574        (format!("{truncated_number} × 10^{length}"), true)
575    } else {
576        (orig_number.to_string(), false)
577    }
578}
579fn format_float(acc: &mut String, number: &Float, consts: &Consts) -> std::fmt::Result {
580    // -a.b x 10^c
581    // -
582    // a
583    // .b
584    // x 10^c
585    let mut number = number.clone();
586    let negative = number.is_sign_negative();
587    number = number.abs();
588    if number == 0 {
589        return acc.write_char('0');
590    }
591    let exponent = number
592        .clone()
593        .log10()
594        .to_integer_round(factorion_math::rug::float::Round::Down)
595        .expect("Could not round exponent")
596        .0;
597    if exponent > consts.number_decimals_scientific
598        || exponent < -(consts.number_decimals_scientific as isize)
599    {
600        number = number / Float::with_val(consts.float_precision, &exponent).exp10();
601    }
602    let mut whole_number = number
603        .to_integer_round(factorion_math::rug::float::Round::Down)
604        .expect("Could not get integer part")
605        .0;
606    let decimal_part = number - &whole_number + 1;
607    let mut decimal_part = format!("{decimal_part}");
608    // Remove "1."
609    decimal_part.remove(0);
610    decimal_part.remove(0);
611    decimal_part.truncate(consts.number_decimals_scientific + 1);
612    if decimal_part.len() > consts.number_decimals_scientific {
613        if round(&mut decimal_part) {
614            decimal_part.clear();
615            whole_number += 1;
616        }
617    }
618    if let Some(mut digit) = decimal_part.pop() {
619        while digit == '0' {
620            digit = match decimal_part.pop() {
621                Some(x) => x,
622                None => break,
623            }
624        }
625        decimal_part.push(digit);
626    }
627    if negative {
628        acc.write_str("-")?;
629    }
630    write!(acc, "{whole_number}")?;
631    if !decimal_part.is_empty() && decimal_part != "0" {
632        acc.write_str(".")?;
633        acc.write_str(&decimal_part)?;
634    }
635    if exponent > consts.number_decimals_scientific
636        || exponent < -(consts.number_decimals_scientific as isize)
637    {
638        write!(acc, " × 10^{exponent}")?;
639    }
640    Ok(())
641}
642
643fn replace(s: &mut String, search_start: usize, from: &str, to: &str) -> usize {
644    if let Some(start) = s[search_start..].find(from) {
645        let start = start + search_start;
646        s.replace_range(start..(start + from.len()), to);
647        start
648    } else {
649        s.len()
650    }
651}
652#[cfg(test)]
653mod tests {
654    use super::*;
655    use crate::recommended::FLOAT_PRECISION;
656    use crate::rug::Integer;
657    use std::{str::FromStr, sync::LazyLock};
658
659    static TOO_BIG_NUMBER: LazyLock<Integer> =
660        LazyLock::new(|| Integer::from_str(&format!("1{}", "0".repeat(9999))).unwrap());
661
662    #[test]
663    fn test_round_down() {
664        let mut number = String::from("1929472373");
665        round(&mut number);
666        assert_eq!(number, "192947237");
667    }
668
669    #[test]
670    fn test_round_up() {
671        let mut number = String::from("74836748625");
672        round(&mut number);
673        assert_eq!(number, "7483674863");
674    }
675
676    #[test]
677    fn test_round_carry() {
678        let mut number = String::from("24999999995");
679        round(&mut number);
680        assert_eq!(number, "25");
681    }
682
683    #[test]
684    fn test_factorial_level_string() {
685        let en = locale::get_en();
686        assert_eq!(
687            Calculation::get_factorial_level_string(1, &en.format()),
688            "{factorial}"
689        );
690        assert_eq!(
691            Calculation::get_factorial_level_string(2, &en.format()),
692            "double-{factorial}"
693        );
694        assert_eq!(
695            Calculation::get_factorial_level_string(3, &en.format()),
696            "triple-{factorial}"
697        );
698        assert_eq!(
699            Calculation::get_factorial_level_string(10, &en.format()),
700            "decuple-{factorial}"
701        );
702        assert_eq!(
703            Calculation::get_factorial_level_string(45, &en.format()),
704            "quinquadragintuple-{factorial}"
705        );
706        assert_eq!(
707            Calculation::get_factorial_level_string(50, &en.format()),
708            "quinquagintuple-{factorial}"
709        );
710        assert_eq!(
711            Calculation::get_factorial_level_string(100, &en.format()),
712            "centuple-{factorial}"
713        );
714        assert_eq!(
715            Calculation::get_factorial_level_string(521, &en.format()),
716            "unviginquingentuple-{factorial}"
717        );
718        assert_eq!(
719            Calculation::get_factorial_level_string(1000, &en.format()),
720            "milluple-{factorial}"
721        );
722        assert_eq!(
723            Calculation::get_factorial_level_string(4321, &en.format()),
724            "unvigintricenquadrilluple-{factorial}"
725        );
726        assert_eq!(
727            Calculation::get_factorial_level_string(10000, &en.format()),
728            "10000-{factorial}"
729        );
730        let de = locale::get_de();
731        assert_eq!(
732            Calculation::get_factorial_level_string(1, &de.format()),
733            "{factorial}"
734        );
735        assert_eq!(
736            Calculation::get_factorial_level_string(2, &de.format()),
737            "doppel{factorial}"
738        );
739        assert_eq!(
740            Calculation::get_factorial_level_string(3, &de.format()),
741            "trippel{factorial}"
742        );
743        assert_eq!(
744            Calculation::get_factorial_level_string(45, &de.format()),
745            "quinquadragintupel{factorial}"
746        );
747    }
748
749    #[test]
750    fn test_truncate() {
751        let consts = Consts::default();
752        assert_eq!(truncate(&Integer::from_str("0").unwrap(), &consts,).0, "0");
753        assert_eq!(
754            truncate(&Integer::from_str("-1").unwrap(), &consts,).0,
755            "-1"
756        );
757        assert_eq!(
758            truncate(
759                &Integer::from_str(&format!("1{}", "0".repeat(300))).unwrap(),
760                &consts
761            )
762            .0,
763            "1 × 10^300"
764        );
765        assert_eq!(
766            truncate(
767                &-Integer::from_str(&format!("1{}", "0".repeat(300))).unwrap(),
768                &consts
769            )
770            .0,
771            "-1 × 10^300"
772        );
773        assert_eq!(
774            truncate(
775                &Integer::from_str(&format!("1{}", "0".repeat(2000000))).unwrap(),
776                &consts
777            )
778            .0,
779            "1 × 10^2000000"
780        );
781    }
782
783    #[test]
784    fn test_format_float() {
785        let consts = Consts::default();
786        let x = Float::with_val(consts.float_precision, 1.5);
787        let mut acc = String::new();
788        format_float(&mut acc, &x, &consts).unwrap();
789        assert_eq!(acc, "1.5");
790        let x = Float::with_val(consts.float_precision, -1.5);
791        let mut acc = String::new();
792        format_float(&mut acc, &x, &consts).unwrap();
793        assert_eq!(acc, "-1.5");
794        let x = Float::with_val(consts.float_precision, 1);
795        let mut acc = String::new();
796        format_float(&mut acc, &x, &consts).unwrap();
797        assert_eq!(acc, "1");
798        let x = Float::with_val(consts.float_precision, 1.5)
799            * Float::with_val(consts.float_precision, 50000).exp10();
800        let mut acc = String::new();
801        format_float(&mut acc, &x, &consts).unwrap();
802        assert_eq!(acc, "1.5 × 10^50000");
803    }
804
805    #[test]
806    fn test_factorial_format() {
807        let consts = Consts::default();
808        let mut acc = String::new();
809        let factorial = Calculation {
810            value: 5.into(),
811            steps: vec![(1, false)],
812            result: CalculationResult::Exact(Integer::from(120)),
813        };
814        factorial
815            .format(
816                &mut acc,
817                false,
818                false,
819                &TOO_BIG_NUMBER,
820                &consts,
821                &consts.locales.get("en").unwrap().format(),
822            )
823            .unwrap();
824        assert_eq!(acc, "Factorial of 5 is 120 \n\n");
825
826        let mut acc = String::new();
827        let factorial = Calculation {
828            value: 5.into(),
829            steps: vec![(0, false)],
830            result: CalculationResult::Exact(Integer::from(120)),
831        };
832        factorial
833            .format(
834                &mut acc,
835                false,
836                false,
837                &TOO_BIG_NUMBER,
838                &consts,
839                &consts.locales.get("en").unwrap().format(),
840            )
841            .unwrap();
842        assert_eq!(acc, "Subfactorial of 5 is 120 \n\n");
843
844        let mut acc = String::new();
845        let factorial = Calculation {
846            value: 5.into(),
847            steps: vec![(1, false)],
848            result: CalculationResult::Approximate(
849                Float::with_val(FLOAT_PRECISION, Float::parse("1.2").unwrap()).into(),
850                5.into(),
851            ),
852        };
853        factorial
854            .format(
855                &mut acc,
856                false,
857                false,
858                &TOO_BIG_NUMBER,
859                &consts,
860                &consts.locales.get("en").unwrap().format(),
861            )
862            .unwrap();
863        assert_eq!(acc, "Factorial of 5 is approximately 1.2 × 10^5 \n\n");
864
865        let mut acc = String::new();
866        let factorial = Calculation {
867            value: 5.into(),
868            steps: vec![(1, false)],
869            result: CalculationResult::ApproximateDigits(false, 3.into()),
870        };
871        factorial
872            .format(
873                &mut acc,
874                false,
875                false,
876                &TOO_BIG_NUMBER,
877                &consts,
878                &consts.locales.get("en").unwrap().format(),
879            )
880            .unwrap();
881        assert_eq!(acc, "Factorial of 5 has approximately 3 digits \n\n");
882
883        let mut acc = String::new();
884        let factorial = Calculation {
885            value: 5.into(),
886            steps: vec![(1, false)],
887            result: CalculationResult::Exact(Integer::from(120)),
888        };
889        factorial
890            .format(
891                &mut acc,
892                true,
893                false,
894                &TOO_BIG_NUMBER,
895                &consts,
896                &consts.locales.get("en").unwrap().format(),
897            )
898            .unwrap();
899        assert_eq!(acc, "Factorial of 5 is 120 \n\n");
900    }
901}
902
903#[cfg(test)]
904mod test {
905    use std::{str::FromStr, sync::LazyLock};
906
907    use factorion_math::rug::Complete;
908
909    use super::*;
910
911    use crate::recommended::FLOAT_PRECISION;
912    static TOO_BIG_NUMBER: LazyLock<Integer> =
913        LazyLock::new(|| Integer::from_str(&format!("1{}", "0".repeat(9999))).unwrap());
914
915    // NOTE: The factorials here might be wrong, but we don't care, we are just testing the formatting
916
917    #[test]
918    fn test_format_factorial() {
919        let consts = Consts::default();
920        let fact = Calculation {
921            value: 10.into(),
922            steps: vec![(3, false)],
923            result: CalculationResult::Exact(280.into()),
924        };
925        let mut s = String::new();
926        fact.format(
927            &mut s,
928            false,
929            false,
930            &TOO_BIG_NUMBER,
931            &consts,
932            &consts.locales.get("en").unwrap().format(),
933        )
934        .unwrap();
935        assert_eq!(s, "Triple-factorial of 10 is 280 \n\n");
936    }
937    #[test]
938    fn test_format_factorial_exact_of_decimal() {
939        let consts = Consts::default();
940        let fact = Calculation {
941            value: Number::Float(Float::with_val(FLOAT_PRECISION, 0.5).into()),
942            steps: vec![(3, false)],
943            result: CalculationResult::Exact(280.into()),
944        };
945        let mut s = String::new();
946        fact.format(
947            &mut s,
948            false,
949            false,
950            &TOO_BIG_NUMBER,
951            &consts,
952            &consts.locales.get("en").unwrap().format(),
953        )
954        .unwrap();
955        assert_eq!(s, "Triple-factorial of 0.5 is approximately 280 \n\n");
956    }
957    #[test]
958    fn test_format_factorial_force_shorten_small() {
959        let consts = Consts::default();
960        let fact = Calculation {
961            value: 10.into(),
962            steps: vec![(3, false)],
963            result: CalculationResult::Exact(280.into()),
964        };
965        let mut s = String::new();
966        fact.format(
967            &mut s,
968            true,
969            false,
970            &TOO_BIG_NUMBER,
971            &consts,
972            &consts.locales.get("en").unwrap().format(),
973        )
974        .unwrap();
975        assert_eq!(s, "Triple-factorial of 10 is 280 \n\n");
976    }
977    #[test]
978    fn test_format_factorial_force_shorten_large() {
979        let consts = Consts::default();
980        let fact = Calculation {
981            value: 100.into(),
982            steps: vec![(1, false)],
983            result: CalculationResult::Exact(
984                Integer::from_str("232019615953125000000000000000000").unwrap(),
985            ),
986        };
987        let mut s = String::new();
988        fact.format(
989            &mut s,
990            false,
991            false,
992            &TOO_BIG_NUMBER,
993            &consts,
994            &consts.locales.get("en").unwrap().format(),
995        )
996        .unwrap();
997        assert_eq!(
998            s,
999            "Factorial of 100 is 232019615953125000000000000000000 \n\n"
1000        );
1001    }
1002    #[test]
1003    fn test_format_factorial_auto_shorten() {
1004        let consts = Consts::default();
1005        let fact = Calculation {
1006            value: 3249.into(),
1007            steps: vec![(1,false)],
1008            result: CalculationResult::Exact(
1009                Integer::from_str("64123376882765521838840963030568127691878727205333658692200854486404915724268122521695176119279253635876611090137291969570276913721864797759577004121543081865516901512445483449601769965060634861857064173938704305418376606356891014609023859758096597956259938348528946750437026172549655426092377089294607836520057856104816993984697675759579496157280331714452191401635250556082973306115574519424960196953201395066132365440977075392087489735146885581823595966673458107135041749084983583726462930633422893526599365244406644257808664472819062579590372326362859263197427382391737724371130194668325697913147795807287917882271125437793075279592752221056089408917956641344121781056494896664298954714463291743622978314854242079926982168325256172879601086193725507405771749789801611825741625380077209528888301112734777086106637653242107578812065387025070985682845983714635115865868052531038040737170581029905537322341939002838113744745962782070030988628668438192063964391415488312555937962867645737183703289987989371752808444472206166983181218698452231772212240017445423758860236449146575513014084114116542491422920779703202877962388772371297148878539228082497149672927873860981295756607109411429871735683677151117763870227460722732815888175758276344884954699572217509595160880510811349033936358665103889507929390456055037630508759624182491412136058522758117862715726418213812122827526330257260872329993280938592007320434494018056858434839424498517707440601396194949605570023576625190771463278168007414358018195714385208103590743168343592988436427551751120123934640886569178657972642734992568217335134536548423867468448461752994160896483162496996197629537563875663545967947035030506174219867102227347745166308776568259737417457622753953177779829173739659562549005900681020920836575654282170728038645671253311902327576757877160190593437037925134089334990083104974051379653937615220306281104735360028696101767109606466502484676624025302461421267416025443536877684785195571046059926349413586237838043863850610251583618438829618642246353724734656122845609571531588284708710081901687161770748138296656576032229319208279032435434327330035540657667361558905445221013396376775953367966087790302411507662731788873698999846238792500590360394500083923341408008981770566937535640769993694293230514231436990415482012055539596871513163008100690298424743718490882019179903258642028365049142613374709689558800856050749214398290563852574062566904927777093160819034619946818734041081848355062039645388238813669985569729968236449074797273410844560761607809842265309788155248298117938165414543689689754240992067831705834383207309250573018855640140957274364918049364842508738871690383100660359882462072065885517245667353800113210423157317762013988734352812105163694758108035856505778854524789188318600594132430921277654972526820920812190785994887939816114878915385423211996897729890266102145491069991647131611614465930571202528403443141981609375073983780241828798986101030035167624885608168623694530984934856402415662119456280967778213695343026782085453754332973412779641743296676142192492849866399186979810426206090031375249707803725234273693273721779240257093247268647749842459507965336971004339619911629224227060334233904444450352505466038312828689977755744971204784911189528493222070017894145493878499832441010771999957866634720057779638435426615168763950876432375766350648344132624416041623318009761058787995614968607413528076499437020919653085121078341947075546317831737787160036257151637941590867306372647047747729689844801136819011517526975033214302293538465503160183447374945622710595033673253137034231320031041035890947260824330728621640030383790059199531556893062561713763583025693789382680375603227866194301270004745201382665157844733507781537231595412109690534099208802055220457258238249940538761563309465648945964188442431661762589082015016756223358648046396366827537498425276338958018446839292802529780142385903309447658806351362744163752044896322012923382835852429065564336560491610071025646451525782856813152304143339115660276089535216189729579966851236899105440783686498435516601131545345163557980985342246336986737955743799192164259513473592703473521185371309681754246866522812455448210758136891890444056252857117200446002038652603259983493405505521897860879586618028713025173570291196046254005672495787117170419665767607647184551353826735583363126537373726390620854105626900247296291639985561481625404296348051054604042180512892657285238147263167051884385297470314430200590079012539964786079859359747123150407661818942489735756835032462952010303051169237940063644470670372188286551571968317499183600768353941744706305961785518398629201507525785967571188931895809109770264983907551256060144219899670118351808815620474425273993244741972143504134827047237929839845492209316520698259428270901257484509899386082594602760813392081897348940617781009158927227690469330327639146118508499255466535663882163793101115885899345523332216762566667486023534622719542192198250458735391090024294254053186440646305309340840685145289223131431157156390489399333752075193525158125680201419183806547205312873264380358849214095835479613319512867197427682723250079990981586869733293245764804577570764831692705888317075918673294669326798053736223321604803330275717540789920865913177228227111643923604665959921096208765542277777829882980225810940866410254096689483571105776785837917708633884075471298045453873223073787369262426626913405098535070631297346400765749139515252242178612533747493270131589184346851060077512732273563896936880596142362061341020737937605198462006142952423931616201569440226926787162077801883794168906567939864710313203688516686488132607069944238278930371283198545637735863991249832218463680910774912311493673518088306563853170521159963238305666024221618323515872866318153226269712890565361382209276094137857215708859605439920538254391240145615109307534437972388439697355227469268959991826344643967606862639207957142695059497774782782862380576527665249011786632721781635858363134217267161265609789721847126531549373639397319541419174824349828634414533913160986280670700117904134971824878639490677063427559640621162799757094469987184056964512589036737188936656494184932005003301076625555129466247988108160104882718140259576746243025950653945267030862681712132414998384138315991964228278130346276982182371619123375659027762342810200791337975076096607162500887202849331840711439619934443487228446573730294798389422723901661778354768525095757656920903185278358954945675520361768231577076750321654682566951617894418024879897723932943778739392625374786945631297844013055183788373235917906391604745846654356151085578611880261515860397623972021392725059655970516681719822949498069366408864396412928494605832710960284204937215373010567096882590065428759248976242854170628853902061231484918006271406155707387649451852150396381227895427254475130432845540997751264574249884576973754475522081887586009543117655192564603663203594121977491966995919938707026254622729082886656923266824175261927609862131917883084745112234024557978747561458733390353402381353061864973111801478933098174668694254024372053350135966105816774315863351432700501507214833910835095241116220945368287364828423032249431110250529198415073098056537298790818802403747860478015395740166511031245261193793854201285682331906071528112005073514650997116494101706639070013374677115821301361236988511929513457351929738018793684759539098410509535113338894579685309152120362751957602730649344150813012563246391457667149097699631546631367291707994927436193366185835774355812730356484690902974319470019544218388669048171395399380611906621586431005917959473642252829970939300283923684023821586277795276767391621510747281802893209607052311085173753725616353413592446675522238914835135290803927878090361225614843018882327106532840756094139114333346621153175254833577042328095480536834801026590432360931424294133543336408702705440236553526213058195627059654976746315636170233701887454392139871178240463495036735780991998499617099173145932919728906603992606395026374552882029156921168342421270810263586384930758466962518032019544198713384832174173447126633137813741748004660781750992387224960402183367639878315847417040125065349322346833085734948541674565230896990919815801676540094611430605654337096768783494147476599630304276589463660992695730097812987784061106253993478908686689107637583574009574525664941872851644555317421340687668414081763994364249671165252652825318436095248164540239487724330276498957490699548343852181838068378612444949106850962864407345130509165857647406496109100001533123176834579856292423765079015513705518869769002090306548513909235083737585930276738943593954668225536658208962591163051195501324651032924378645456520478535714079874404144783894706654731307268880764144813567558473827034967105368425271973138213726718055181321006250745589786136935583735915890517993411416086214277469794370188740010736604373520529352427775875772577651690552630708696044935360500197728514057299685757816479040563926362665221456966339198099627395349937057349473111399655105587183432516687910987518148931239145857422059143761070545360054386871218955184209375241453611589548642653321253873363792347807426924575722280463634222994099258528815002881358362491008896204800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap()
1010            ),
1011        };
1012        let mut s = String::new();
1013        fact.format(
1014            &mut s,
1015            false,
1016            false,
1017            &TOO_BIG_NUMBER,
1018            &consts,
1019            &consts.locales.get("en").unwrap().format(),
1020        )
1021        .unwrap();
1022        assert_eq!(
1023            s,
1024            "Factorial of 3249 is roughly 6.412337688276552183884096303057 × 10^10000 \n\n"
1025        );
1026    }
1027    #[test]
1028    fn test_format_factorial_chain() {
1029        let consts = Consts::default();
1030        let fact = Calculation {
1031            value: 5.into(),
1032            steps: vec![(3, false), (1, false)],
1033            result: CalculationResult::Exact(3628800.into()),
1034        };
1035        let mut s = String::new();
1036        fact.format(
1037            &mut s,
1038            false,
1039            false,
1040            &TOO_BIG_NUMBER,
1041            &consts,
1042            &consts.locales.get("en").unwrap().format(),
1043        )
1044        .unwrap();
1045        assert_eq!(s, "Factorial of triple-factorial of 5 is 3628800 \n\n");
1046    }
1047    #[test]
1048    fn test_format_factorial_negative() {
1049        let consts = Consts::default();
1050        let fact = Calculation {
1051            value: 0.into(),
1052            steps: vec![(1, true)],
1053            result: CalculationResult::Exact(3628800.into()),
1054        };
1055        let mut s = String::new();
1056        fact.format(
1057            &mut s,
1058            false,
1059            false,
1060            &TOO_BIG_NUMBER,
1061            &consts,
1062            &consts.locales.get("en").unwrap().format(),
1063        )
1064        .unwrap();
1065        assert_eq!(s, "Negative factorial of 0 is 3628800 \n\n");
1066    }
1067    #[test]
1068    fn test_format_approximate_factorial() {
1069        let consts = Consts::default();
1070        let fact = Calculation {
1071            value: 0.into(),
1072            steps: vec![(1, false)],
1073            result: CalculationResult::Approximate(
1074                Float::with_val(FLOAT_PRECISION, Float::parse("2.83947").unwrap()).into(),
1075                10043.into(),
1076            ),
1077        };
1078        let mut s = String::new();
1079        fact.format(
1080            &mut s,
1081            false,
1082            false,
1083            &TOO_BIG_NUMBER,
1084            &consts,
1085            &consts.locales.get("en").unwrap().format(),
1086        )
1087        .unwrap();
1088        assert_eq!(s, "Factorial of 0 is approximately 2.83947 × 10^10043 \n\n");
1089    }
1090    #[test]
1091    fn test_format_approximate_digits_factorial() {
1092        let consts = Consts::default();
1093        let fact = Calculation {
1094            value: 0.into(),
1095            steps: vec![(1, false)],
1096            result: CalculationResult::ApproximateDigits(false, 10043394.into()),
1097        };
1098        let mut s = String::new();
1099        fact.format(
1100            &mut s,
1101            false,
1102            false,
1103            &TOO_BIG_NUMBER,
1104            &consts,
1105            &consts.locales.get("en").unwrap().format(),
1106        )
1107        .unwrap();
1108        assert_eq!(s, "Factorial of 0 has approximately 10043394 digits \n\n");
1109    }
1110    #[test]
1111    fn test_format_complex_infinity_factorial() {
1112        let consts = Consts::default();
1113        let fact = Calculation {
1114            value: 0.into(),
1115            steps: vec![(1, false)],
1116            result: CalculationResult::ComplexInfinity,
1117        };
1118        let mut s = String::new();
1119        fact.format(
1120            &mut s,
1121            false,
1122            false,
1123            &TOO_BIG_NUMBER,
1124            &consts,
1125            &consts.locales.get("en").unwrap().format(),
1126        )
1127        .unwrap();
1128        assert_eq!(s, "Factorial of 0 is ∞\u{0303} \n\n");
1129    }
1130    #[test]
1131    fn test_format_digits_tower() {
1132        let consts = Consts::default();
1133        let fact = Calculation {
1134            value: 0.into(),
1135            steps: vec![(1, false)],
1136            result: CalculationResult::ApproximateDigitsTower(false, false, 9.into(), 10375.into()),
1137        };
1138        let mut s = String::new();
1139        fact.format(
1140            &mut s,
1141            false,
1142            false,
1143            &TOO_BIG_NUMBER,
1144            &consts,
1145            &consts.locales.get("en").unwrap().format(),
1146        )
1147        .unwrap();
1148        assert_eq!(
1149            s,
1150            "Factorial of 0 has on the order of 10^(10\\^10\\^10\\^10\\^10\\^10\\^10\\^10\\^(10375\\)) digits \n\n"
1151        );
1152    }
1153    #[test]
1154    fn test_format_digits_tower_negative() {
1155        let consts = Consts::default();
1156        let fact = Calculation {
1157            value: 0.into(),
1158            steps: vec![(1, false)],
1159            result: CalculationResult::ApproximateDigitsTower(false, true, 9.into(), 10375.into()),
1160        };
1161        let mut s = String::new();
1162        fact.format(
1163            &mut s,
1164            false,
1165            false,
1166            &TOO_BIG_NUMBER,
1167            &consts,
1168            &consts.locales.get("en").unwrap().format(),
1169        )
1170        .unwrap();
1171        assert_eq!(
1172            s,
1173            "Factorial of 0 has on the order of -10^(10\\^10\\^10\\^10\\^10\\^10\\^10\\^10\\^(10375\\)) digits \n\n"
1174        );
1175    }
1176    #[test]
1177    fn test_format_digits_tower_tet() {
1178        let consts = Consts::default();
1179        let fact = Calculation {
1180            value: 0.into(),
1181            steps: vec![(1, false), (1, false)],
1182            result: CalculationResult::ApproximateDigitsTower(false, false, 9.into(), 10375.into()),
1183        };
1184        let mut s = String::new();
1185        fact.format(
1186            &mut s,
1187            false,
1188            true,
1189            &TOO_BIG_NUMBER,
1190            &consts,
1191            &consts.locales.get("en").unwrap().format(),
1192        )
1193        .unwrap();
1194        assert_eq!(s, "All that of 0 has on the order of ^(10)10 digits \n\n");
1195    }
1196    #[test]
1197    fn test_format_gamma() {
1198        let consts = Consts::default();
1199        let fact = Calculation {
1200            value: Number::Float(
1201                Float::with_val(FLOAT_PRECISION, Float::parse("9.2").unwrap()).into(),
1202            ),
1203            steps: vec![(1, false)],
1204            result: CalculationResult::Float(
1205                Float::with_val(FLOAT_PRECISION, Float::parse("893.83924421").unwrap()).into(),
1206            ),
1207        };
1208        let mut s = String::new();
1209        fact.format(
1210            &mut s,
1211            false,
1212            false,
1213            &TOO_BIG_NUMBER,
1214            &consts,
1215            &consts.locales.get("en").unwrap().format(),
1216        )
1217        .unwrap();
1218        assert_eq!(s, "Factorial of 9.2 is approximately 893.83924421 \n\n");
1219    }
1220    #[test]
1221    fn test_format_gamma_fallback() {
1222        let consts = Consts::default();
1223        let fact = Calculation {
1224            value: Number::Float(Float::with_val(FLOAT_PRECISION, 0).into()),
1225            steps: vec![(1, false)],
1226            result: {
1227                let mut m = Float::with_val(FLOAT_PRECISION, f64::MAX);
1228                m.next_up();
1229                CalculationResult::Float(m.into())
1230            },
1231        };
1232        let mut s = String::new();
1233        fact.format(
1234            &mut s,
1235            false,
1236            false,
1237            &TOO_BIG_NUMBER,
1238            &consts,
1239            &consts.locales.get("en").unwrap().format(),
1240        )
1241        .unwrap();
1242        assert_eq!(
1243            s,
1244            "Factorial of 0 is approximately 1.797693134862315708145274237317 × 10^308 \n\n"
1245        );
1246    }
1247    #[test]
1248    fn test_format_approximate_factorial_shorten() {
1249        let consts = Consts::default();
1250        let fact = Calculation {
1251            value: Number::Exact(
1252                Integer::from_str("2018338437429423744923849374833232131").unwrap(),
1253            ),
1254            steps: vec![(1, false)],
1255            result: CalculationResult::Approximate(
1256                Float::with_val(FLOAT_PRECISION, Float::parse("2.8394792834").unwrap()).into(),
1257                Integer::from_str("10094283492304894983443984102489842984271").unwrap(),
1258            ),
1259        };
1260        let mut s = String::new();
1261        fact.format(
1262            &mut s,
1263            true,
1264            false,
1265            &TOO_BIG_NUMBER,
1266            &consts,
1267            &consts.locales.get("en").unwrap().format(),
1268        )
1269        .unwrap();
1270        assert_eq!(
1271            s,
1272            "Factorial of roughly 2.018338437429423744923849374833 × 10^36 is approximately 2.8394792834 × 10^(1.009428349230489498344398410249 × 10^40) \n\n"
1273        );
1274    }
1275    #[test]
1276    fn test_format_approximate_digits_factorial_shorten() {
1277        let consts = Consts::default();
1278        let fact = Calculation {
1279            value: Number::Exact(
1280                Integer::from_str("2313820948092579283573259490834298719").unwrap(),
1281            ),
1282            steps: vec![(1, false)],
1283            result: CalculationResult::ApproximateDigits(
1284                false,
1285                Integer::from_str("9842371208573508275237815084709374240128347012847").unwrap(),
1286            ),
1287        };
1288        let mut s = String::new();
1289        fact.format(
1290            &mut s,
1291            true,
1292            false,
1293            &TOO_BIG_NUMBER,
1294            &consts,
1295            &consts.locales.get("en").unwrap().format(),
1296        )
1297        .unwrap();
1298        assert_eq!(
1299            s,
1300            "Factorial of roughly 2.313820948092579283573259490834 × 10^36 has approximately 9.842371208573508275237815084709 × 10^48 digits \n\n"
1301        );
1302    }
1303    #[test]
1304    fn test_format_digits_tower_shorten() {
1305        let consts = Consts::default();
1306        let fact = Calculation {
1307            value: Number::Exact(
1308                Integer::from_str("13204814708471087502685784603872164320053271").unwrap(),
1309            ),
1310            steps: vec![(1, false)],
1311            result: CalculationResult::ApproximateDigitsTower(
1312                false,
1313                false,
1314                9.into(),
1315                Integer::from_str("7084327410873502875032857120358730912469148632").unwrap(),
1316            ),
1317        };
1318        let mut s = String::new();
1319        fact.format(
1320            &mut s,
1321            true,
1322            false,
1323            &TOO_BIG_NUMBER,
1324            &consts,
1325            &consts.locales.get("en").unwrap().format(),
1326        )
1327        .unwrap();
1328        assert_eq!(
1329            s,
1330            "Factorial of roughly 1.320481470847108750268578460387 × 10^43 has on the order of 10^(10\\^10\\^10\\^10\\^10\\^10\\^10\\^10\\^(7.084327410873502875032857120359 × 10^45\\)) digits \n\n"
1331        );
1332    }
1333    #[test]
1334    fn test_format_huge() {
1335        let consts = Consts::default();
1336        let fact = Calculation {
1337            value: 0.into(),
1338            steps: vec![(1, false)],
1339            result: CalculationResult::Exact({
1340                let mut r = Float::with_val(FLOAT_PRECISION, crate::rug::float::Special::Infinity);
1341                r.next_down();
1342                r.to_integer().unwrap()
1343            }),
1344        };
1345        let mut s = String::new();
1346        fact.format(
1347            &mut s,
1348            false,
1349            false,
1350            &TOO_BIG_NUMBER,
1351            &consts,
1352            &consts.locales.get("en").unwrap().format(),
1353        )
1354        .unwrap();
1355        assert_eq!(
1356            s,
1357            "Factorial of 0 is roughly 2.098578716467387692404358116884 × 10^323228496 \n\n"
1358        );
1359    }
1360
1361    #[test]
1362    fn test_tower_value_with_one_top() {
1363        let consts = Consts::default();
1364        let fact = Calculation {
1365            value: 0.into(),
1366            steps: vec![(1, false)],
1367            result: CalculationResult::ApproximateDigitsTower(false, false, 4.into(), 1.into()),
1368        };
1369        let mut s = String::new();
1370        fact.format(
1371            &mut s,
1372            false,
1373            false,
1374            &TOO_BIG_NUMBER,
1375            &consts,
1376            &consts.locales.get("en").unwrap().format(),
1377        )
1378        .unwrap();
1379        assert_eq!(s, "Factorial of 0 has on the order of ^(4)10 digits \n\n");
1380    }
1381
1382    #[test]
1383    fn test_calculation_is_approximate() {
1384        let c1 = Calculation {
1385            value: 0.into(),
1386            steps: vec![],
1387            result: CalculationResult::Approximate(
1388                Float::with_val(FLOAT_PRECISION, 2.0).into(),
1389                1.into(),
1390            ),
1391        };
1392        assert!(c1.is_approximate());
1393        let c2 = Calculation {
1394            value: 0.into(),
1395            steps: vec![],
1396            result: CalculationResult::Exact(1.into()),
1397        };
1398        assert!(!c2.is_approximate());
1399    }
1400
1401    #[test]
1402    fn test_calculation_is_rounded() {
1403        let c1 = Calculation {
1404            value: Number::Float(Float::with_val(FLOAT_PRECISION, 1.23).into()),
1405            steps: vec![],
1406            result: CalculationResult::Approximate(
1407                Float::with_val(FLOAT_PRECISION, 0.0).into(),
1408                0.into(),
1409            ),
1410        };
1411        assert!(c1.is_rounded());
1412        let c2 = Calculation {
1413            value: Number::Float(Float::with_val(FLOAT_PRECISION, 1.23).into()),
1414            steps: vec![],
1415            result: CalculationResult::Float(Float::with_val(FLOAT_PRECISION, 1.23).into()),
1416        };
1417        assert!(!c2.is_rounded());
1418        let c3 = Calculation {
1419            value: 1.into(),
1420            steps: vec![],
1421            result: CalculationResult::Exact(1.into()),
1422        };
1423        assert!(!c3.is_rounded());
1424    }
1425
1426    #[test]
1427    fn test_is_too_long() {
1428        let small = Calculation {
1429            value: 1.into(),
1430            steps: vec![],
1431            result: CalculationResult::Exact(1.into()),
1432        };
1433        assert!(!small.is_too_long(&TOO_BIG_NUMBER));
1434        let big = Calculation {
1435            value: 1.into(),
1436            steps: vec![],
1437            result: CalculationResult::Exact((*TOO_BIG_NUMBER).clone() + 1),
1438        };
1439        assert!(big.is_too_long(&TOO_BIG_NUMBER));
1440        let fl = Calculation {
1441            value: 1.into(),
1442            steps: vec![],
1443            result: CalculationResult::Float(Float::with_val(FLOAT_PRECISION, 1.0).into()),
1444        };
1445        assert!(!fl.is_too_long(&TOO_BIG_NUMBER));
1446    }
1447
1448    #[test]
1449    fn test_number_decimals_scientific_respected() {
1450        let mut consts = Consts::default();
1451        consts.number_decimals_scientific = 10;
1452        let mut acc = String::new();
1453        CalculationResult::Exact(Integer::u_pow_u(10, 1000).complete() * 498149837492347328u64)
1454            .format(
1455                &mut acc,
1456                &mut false,
1457                true,
1458                false,
1459                false,
1460                &consts,
1461                &locale::NumFormat::V1(&locale::v1::NumFormat { decimal: '.' }),
1462            )
1463            .unwrap();
1464        assert_eq!(acc, "4.9814983749 × 10^1017");
1465        let mut acc = String::new();
1466        CalculationResult::Approximate(
1467            Float::with_val(FLOAT_PRECISION, 4.98149837492347328f64).into(),
1468            1017.into(),
1469        )
1470        .format(
1471            &mut acc,
1472            &mut false,
1473            true,
1474            false,
1475            false,
1476            &consts,
1477            &locale::NumFormat::V1(&locale::v1::NumFormat { decimal: '.' }),
1478        )
1479        .unwrap();
1480        assert_eq!(acc, "4.9814983749 × 10^(1017)");
1481        consts.number_decimals_scientific = 50;
1482        let mut acc = String::new();
1483        CalculationResult::Exact(
1484            Integer::u_pow_u(10, 1000).complete() * 49814983749234732849839849898438493843u128,
1485        )
1486        .format(
1487            &mut acc,
1488            &mut false,
1489            true,
1490            false,
1491            false,
1492            &consts,
1493            &locale::NumFormat::V1(&locale::v1::NumFormat { decimal: '.' }),
1494        )
1495        .unwrap();
1496        assert_eq!(acc, "4.9814983749234732849839849898438493843 × 10^1037");
1497        let mut acc = String::new();
1498        CalculationResult::Approximate(
1499            Float::with_val(
1500                FLOAT_PRECISION,
1501                Float::parse("4.9814983749234732849839849898438493843").unwrap(),
1502            )
1503            .into(),
1504            1037.into(),
1505        )
1506        .format(
1507            &mut acc,
1508            &mut false,
1509            true,
1510            false,
1511            false,
1512            &consts,
1513            &locale::NumFormat::V1(&locale::v1::NumFormat { decimal: '.' }),
1514        )
1515        .unwrap();
1516        assert_eq!(acc, "4.9814983749234732849839849898438493843 × 10^(1037)");
1517    }
1518    #[test]
1519    fn test_format_float() {
1520        let mut consts = Consts::default();
1521        let mut acc = String::new();
1522        format_float(
1523            &mut acc,
1524            &Float::with_val(
1525                FLOAT_PRECISION,
1526                Float::parse("0.999999999999999999999999999999999").unwrap(),
1527            ),
1528            &consts,
1529        )
1530        .unwrap();
1531        assert_eq!(acc, "1");
1532        let mut acc = String::new();
1533        format_float(
1534            &mut acc,
1535            &Float::with_val(
1536                FLOAT_PRECISION,
1537                Float::parse("0.000000000000000000000000000000009").unwrap(),
1538            ),
1539            &consts,
1540        )
1541        .unwrap();
1542        assert_eq!(acc, "9 × 10^-33");
1543        consts.number_decimals_scientific = 2;
1544        acc.clear();
1545        format_float(
1546            &mut acc,
1547            &Float::with_val(FLOAT_PRECISION, Float::parse("0.10").unwrap()),
1548            &consts,
1549        )
1550        .unwrap();
1551        assert_eq!(acc, "0.1");
1552
1553        let consts = Consts::default();
1554        acc.clear();
1555        format_float(
1556            &mut acc,
1557            &Float::with_val(FLOAT_PRECISION, Float::parse("6.631537423e-34").unwrap()),
1558            &consts,
1559        )
1560        .unwrap();
1561        assert_eq!(acc, "6.631537423 × 10^-34");
1562        let consts = Consts::default();
1563        acc.clear();
1564        format_float(
1565            &mut acc,
1566            &Float::with_val(FLOAT_PRECISION, Float::parse("6.631537423e34").unwrap()),
1567            &consts,
1568        )
1569        .unwrap();
1570        assert_eq!(acc, "6.631537423 × 10^34");
1571    }
1572}