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