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