Skip to main content

factorion_lib/
calculation_results.rs

1//! This module handles the formatting of the calculations (`The factorial of Subfactorial of 5 is`, etc.)
2
3#[cfg(any(feature = "serde", test))]
4use serde::{Deserialize, Serialize};
5
6use crate::rug::float::OrdFloat;
7use crate::rug::ops::{NegAssign, NotAssign, Pow};
8use crate::rug::{Float, Integer};
9use crate::{Consts, locale};
10use std::borrow::Cow;
11use std::fmt;
12use std::fmt::Write;
13
14pub mod recommended {
15    pub const NUMBER_DECIMALS_SCIENTIFIC: usize = 30;
16}
17
18impl fmt::Debug for CalculationResult {
19    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20        fn truncate<T: fmt::Debug>(val: &T) -> String {
21            let s = format!("{val:?}");
22            if s.len() > 25 {
23                format!("{}...", &s[..20])
24            } else {
25                s
26            }
27        }
28
29        match self {
30            CalculationResult::Exact(n) => write!(f, "Exact({})", truncate(n)),
31            CalculationResult::Approximate(of, int) => {
32                write!(
33                    f,
34                    "Approximate({}, {})",
35                    truncate(&of.as_float()),
36                    truncate(int)
37                )
38            }
39            CalculationResult::ApproximateDigits(i, n) => {
40                write!(f, "ApproximateDigits({}, {})", i, truncate(n))
41            }
42            CalculationResult::ApproximateDigitsTower(i, b, u, n) => {
43                write!(
44                    f,
45                    "ApproximateDigitsTower({}, {}, {}, {})",
46                    i,
47                    b,
48                    u,
49                    truncate(n)
50                )
51            }
52            CalculationResult::Float(of) => write!(f, "Float({})", truncate(&of.as_float())),
53            CalculationResult::ComplexInfinity => write!(f, "ComplexInfinity"),
54        }
55    }
56}
57
58/// The result of a calculation in various formats.
59#[derive(Clone, PartialEq, Ord, Eq, Hash, PartialOrd)]
60#[cfg_attr(any(feature = "serde", test), derive(Serialize, Deserialize))]
61pub enum CalculationResult {
62    Exact(Integer),
63    /// a * 10^b
64    Approximate(OrdFloat, Integer),
65    /// b digits (a is whether the number is negative)
66    ApproximateDigits(bool, Integer),
67    /// (^(c)10)^d digits (a is whether is negative, b is negative number of digits (super small))
68    ApproximateDigitsTower(bool, bool, Integer, Integer),
69    Float(OrdFloat),
70    ComplexInfinity,
71}
72
73/// A number in various formats. An alias of [CalculationResult].
74pub type Number = CalculationResult;
75
76impl Number {
77    pub fn negate(&mut self) {
78        match self {
79            Self::Approximate(x, _) | Self::Float(x) => x.as_float_mut().neg_assign(),
80            Self::Exact(n) => n.neg_assign(),
81            Self::ApproximateDigitsTower(n, _, _, _) | Self::ApproximateDigits(n, _) => {
82                n.not_assign()
83            }
84            Self::ComplexInfinity => {}
85        }
86    }
87    pub fn is_too_long(&self, too_big_number: &Integer) -> bool {
88        let n = match self {
89            CalculationResult::Exact(n)
90            | CalculationResult::ApproximateDigits(_, n)
91            | CalculationResult::Approximate(_, n)
92            | CalculationResult::ApproximateDigitsTower(_, _, _, n) => n,
93            CalculationResult::Float(_) | CalculationResult::ComplexInfinity => return false,
94        };
95        n > too_big_number
96    }
97}
98impl From<Integer> for Number {
99    fn from(value: Integer) -> Self {
100        Number::Exact(value)
101    }
102}
103impl From<i32> for Number {
104    fn from(value: i32) -> Self {
105        Number::Exact(value.into())
106    }
107}
108impl From<Float> for Number {
109    fn from(value: Float) -> Self {
110        Number::Float(value.into())
111    }
112}
113
114impl CalculationResult {
115    /// Formats a number. \
116    /// Shorten turns integers into scientific notation if that makes them shorter. \
117    /// Aggressive enables tertation for towers.
118    fn format(
119        &self,
120        acc: &mut String,
121        rough: &mut bool,
122        shorten: bool,
123        agressive: bool,
124        is_value: bool,
125        consts: &Consts,
126        locale: &locale::NumFormat,
127    ) -> std::fmt::Result {
128        let mut start = acc.len();
129        match &self {
130            CalculationResult::Exact(factorial) => {
131                if shorten {
132                    let (s, r) = truncate(factorial, consts);
133                    *rough = r;
134                    acc.write_str(&s)?;
135                } else {
136                    write!(acc, "{factorial}")?;
137                }
138            }
139            CalculationResult::Approximate(base, exponent) => {
140                let base = base.as_float();
141                format_float(acc, base, consts)?;
142                acc.write_str(" × 10^")?;
143                if shorten {
144                    acc.write_str("(")?;
145                    acc.write_str(&truncate(exponent, consts).0)?;
146                    acc.write_str(")")?;
147                } else {
148                    write!(acc, "{exponent}")?;
149                }
150            }
151            CalculationResult::ApproximateDigits(_, digits) => {
152                if is_value {
153                    acc.write_str("10^(")?;
154                }
155                if shorten {
156                    acc.write_str(&truncate(digits, consts).0)?;
157                } else {
158                    write!(acc, "{digits}")?;
159                }
160                if is_value {
161                    acc.write_str(")")?;
162                }
163            }
164            CalculationResult::ApproximateDigitsTower(_, negative, depth, exponent) => {
165                let depth = if is_value {
166                    depth.clone() + 1
167                } else {
168                    depth.clone()
169                };
170                acc.write_str(if *negative { "-" } else { "" })?;
171                // If we have a one on top, we gain no information by printing the whole tower.
172                // If depth is one, it is nicer to write 10¹ than ¹10.
173                if !agressive && depth <= usize::MAX && (depth <= 1 || exponent != &1) {
174                    if depth > 0 {
175                        acc.write_str("10^(")?;
176                    }
177                    if depth > 1 {
178                        // PANIC: We just checked, that it is <= usize::MAX and > 1 (implies >= 0), so it fits in usize
179                        acc.write_str(&"10\\^".repeat(depth.to_usize().unwrap() - 1))?;
180                        acc.write_str("(")?;
181                    }
182                    if shorten {
183                        acc.write_str(&truncate(exponent, consts).0)?;
184                    } else {
185                        write!(acc, "{exponent}")?;
186                    }
187                    if depth > 1 {
188                        acc.write_str("\\)")?;
189                    }
190                    if depth > 0 {
191                        acc.write_str(")")?;
192                    }
193                } else {
194                    let mut extra = 0;
195                    let mut exponent = Float::with_val(consts.float_precision, exponent);
196                    while exponent >= 10 {
197                        extra += 1;
198                        exponent = exponent.log10();
199                    }
200                    acc.write_str("^(")?;
201                    write!(acc, "{}", depth + extra)?;
202                    acc.write_str(")10")?;
203                }
204            }
205            CalculationResult::Float(gamma) => {
206                let gamma = gamma.as_float();
207                format_float(acc, gamma, consts)?;
208            }
209            CalculationResult::ComplexInfinity => {
210                acc.write_str("∞\u{0303}")?;
211            }
212        }
213        if *locale.decimal() != '.' {
214            let decimal = locale.decimal().to_string();
215            while start < acc.len() {
216                start = replace(acc, start, ".", &decimal);
217            }
218        }
219        Ok(())
220    }
221}
222
223#[derive(Debug, Clone, PartialEq, Ord, Eq, Hash, PartialOrd)]
224#[cfg_attr(any(feature = "serde", test), derive(Serialize, Deserialize))]
225pub struct Calculation {
226    /// The base number
227    pub value: Number,
228    /// Steps taken during calculation (level, negation)
229    pub steps: Vec<(i32, bool)>,
230    pub result: CalculationResult,
231}
232
233impl Calculation {
234    pub fn is_digit_tower(&self) -> bool {
235        matches!(
236            self,
237            Calculation {
238                result: CalculationResult::ApproximateDigitsTower(_, _, _, _),
239                ..
240            }
241        )
242    }
243    pub fn is_aproximate_digits(&self) -> bool {
244        matches!(
245            self,
246            Calculation {
247                result: CalculationResult::ApproximateDigits(_, _),
248                ..
249            }
250        )
251    }
252    pub fn is_approximate(&self) -> bool {
253        matches!(
254            self,
255            Calculation {
256                result: CalculationResult::Approximate(_, _),
257                ..
258            }
259        )
260    }
261    pub fn is_rounded(&self) -> bool {
262        matches!(
263            self,
264            Calculation {
265                value: Number::Float(_),
266                ..
267            }
268        ) && !matches!(
269            self,
270            Calculation {
271                result: CalculationResult::Float(_),
272                ..
273            }
274        )
275    }
276    pub fn is_too_long(&self, too_big_number: &Integer) -> bool {
277        self.result.is_too_long(too_big_number) || self.value.is_too_long(too_big_number)
278    }
279}
280
281impl Calculation {
282    /// Formats a Calcucation. \
283    /// Force shorten shortens all integers, if that makes them smaller. \
284    /// Agressive shorten replaces the description of what steps were taken with "All that of" and truns towers into tetration. \
285    /// Too big number is from when the integer part automatically gets shortened.
286    pub fn format(
287        &self,
288        acc: &mut String,
289        force_shorten: bool,
290        agressive_shorten: bool,
291        too_big_number: &Integer,
292        consts: &Consts,
293        locale: &locale::Format<'_>,
294    ) -> Result<(), std::fmt::Error> {
295        let frame_start = acc.len();
296        acc.write_str(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    // -
573    // a
574    // .b
575    // x 10^c
576    let mut number = number.clone();
577    let negative = number.is_sign_negative();
578    number = number.abs();
579    let exponent = number
580        .clone()
581        .log10()
582        .max(&Float::new(consts.float_precision))
583        .to_integer_round(factorion_math::rug::float::Round::Down)
584        .expect("Could not round exponent")
585        .0;
586    if exponent > consts.number_decimals_scientific {
587        number = number / Float::with_val(consts.float_precision, &exponent).exp10();
588    }
589    let whole_number = number
590        .to_integer_round(factorion_math::rug::float::Round::Down)
591        .expect("Could not get integer part")
592        .0;
593    let decimal_part = number - &whole_number + 1;
594    let mut decimal_part = format!("{decimal_part}");
595    // Remove "1."
596    decimal_part.remove(0);
597    decimal_part.remove(0);
598    decimal_part.truncate(consts.number_decimals_scientific + 1);
599    if decimal_part.len() > consts.number_decimals_scientific {
600        round(&mut decimal_part);
601    }
602    if let Some(mut digit) = decimal_part.pop() {
603        while digit == '0' {
604            digit = match decimal_part.pop() {
605                Some(x) => x,
606                None => break,
607            }
608        }
609        decimal_part.push(digit);
610    }
611    if negative {
612        acc.write_str("-")?;
613    }
614    write!(acc, "{whole_number}")?;
615    if !decimal_part.is_empty() && decimal_part != "0" {
616        acc.write_str(".")?;
617        acc.write_str(&decimal_part)?;
618    }
619    if exponent > consts.number_decimals_scientific {
620        write!(acc, " × 10^{exponent}")?;
621    }
622    Ok(())
623}
624
625fn replace(s: &mut String, search_start: usize, from: &str, to: &str) -> usize {
626    if let Some(start) = s[search_start..].find(from) {
627        let start = start + search_start;
628        s.replace_range(start..(start + from.len()), to);
629        start
630    } else {
631        s.len()
632    }
633}
634#[cfg(test)]
635mod tests {
636    use super::*;
637    use crate::recommended::FLOAT_PRECISION;
638    use crate::rug::Integer;
639    use std::{str::FromStr, sync::LazyLock};
640
641    static TOO_BIG_NUMBER: LazyLock<Integer> =
642        LazyLock::new(|| Integer::from_str(&format!("1{}", "0".repeat(9999))).unwrap());
643
644    #[test]
645    fn test_round_down() {
646        let mut number = String::from("1929472373");
647        round(&mut number);
648        assert_eq!(number, "192947237");
649    }
650
651    #[test]
652    fn test_round_up() {
653        let mut number = String::from("74836748625");
654        round(&mut number);
655        assert_eq!(number, "7483674863");
656    }
657
658    #[test]
659    fn test_round_carry() {
660        let mut number = String::from("24999999995");
661        round(&mut number);
662        assert_eq!(number, "25");
663    }
664
665    #[test]
666    fn test_factorial_level_string() {
667        let en = locale::get_en();
668        assert_eq!(
669            Calculation::get_factorial_level_string(1, &en.format()),
670            "{factorial}"
671        );
672        assert_eq!(
673            Calculation::get_factorial_level_string(2, &en.format()),
674            "double-{factorial}"
675        );
676        assert_eq!(
677            Calculation::get_factorial_level_string(3, &en.format()),
678            "triple-{factorial}"
679        );
680        assert_eq!(
681            Calculation::get_factorial_level_string(10, &en.format()),
682            "decuple-{factorial}"
683        );
684        assert_eq!(
685            Calculation::get_factorial_level_string(45, &en.format()),
686            "quinquadragintuple-{factorial}"
687        );
688        assert_eq!(
689            Calculation::get_factorial_level_string(50, &en.format()),
690            "quinquagintuple-{factorial}"
691        );
692        assert_eq!(
693            Calculation::get_factorial_level_string(100, &en.format()),
694            "centuple-{factorial}"
695        );
696        assert_eq!(
697            Calculation::get_factorial_level_string(521, &en.format()),
698            "unviginquingentuple-{factorial}"
699        );
700        assert_eq!(
701            Calculation::get_factorial_level_string(1000, &en.format()),
702            "milluple-{factorial}"
703        );
704        assert_eq!(
705            Calculation::get_factorial_level_string(4321, &en.format()),
706            "unvigintricenquadrilluple-{factorial}"
707        );
708        assert_eq!(
709            Calculation::get_factorial_level_string(10000, &en.format()),
710            "10000-{factorial}"
711        );
712        let de = locale::get_de();
713        assert_eq!(
714            Calculation::get_factorial_level_string(1, &de.format()),
715            "{factorial}"
716        );
717        assert_eq!(
718            Calculation::get_factorial_level_string(2, &de.format()),
719            "doppel{factorial}"
720        );
721        assert_eq!(
722            Calculation::get_factorial_level_string(3, &de.format()),
723            "trippel{factorial}"
724        );
725        assert_eq!(
726            Calculation::get_factorial_level_string(45, &de.format()),
727            "quinquadragintupel{factorial}"
728        );
729    }
730
731    #[test]
732    fn test_truncate() {
733        let consts = Consts::default();
734        assert_eq!(truncate(&Integer::from_str("0").unwrap(), &consts,).0, "0");
735        assert_eq!(
736            truncate(&Integer::from_str("-1").unwrap(), &consts,).0,
737            "-1"
738        );
739        assert_eq!(
740            truncate(
741                &Integer::from_str(&format!("1{}", "0".repeat(300))).unwrap(),
742                &consts
743            )
744            .0,
745            "1 × 10^300"
746        );
747        assert_eq!(
748            truncate(
749                &-Integer::from_str(&format!("1{}", "0".repeat(300))).unwrap(),
750                &consts
751            )
752            .0,
753            "-1 × 10^300"
754        );
755        assert_eq!(
756            truncate(
757                &Integer::from_str(&format!("1{}", "0".repeat(2000000))).unwrap(),
758                &consts
759            )
760            .0,
761            "1 × 10^2000000"
762        );
763    }
764
765    #[test]
766    fn test_format_float() {
767        let consts = Consts::default();
768        let x = Float::with_val(consts.float_precision, 1.5);
769        let mut acc = String::new();
770        format_float(&mut acc, &x, &consts).unwrap();
771        assert_eq!(acc, "1.5");
772        let x = Float::with_val(consts.float_precision, -1.5);
773        let mut acc = String::new();
774        format_float(&mut acc, &x, &consts).unwrap();
775        assert_eq!(acc, "-1.5");
776        let x = Float::with_val(consts.float_precision, 1);
777        let mut acc = String::new();
778        format_float(&mut acc, &x, &consts).unwrap();
779        assert_eq!(acc, "1");
780        let x = Float::with_val(consts.float_precision, 1.5)
781            * Float::with_val(consts.float_precision, 50000).exp10();
782        let mut acc = String::new();
783        format_float(&mut acc, &x, &consts).unwrap();
784        assert_eq!(acc, "1.5 × 10^50000");
785    }
786
787    #[test]
788    fn test_factorial_format() {
789        let consts = Consts::default();
790        let mut acc = String::new();
791        let factorial = Calculation {
792            value: 5.into(),
793            steps: vec![(1, false)],
794            result: CalculationResult::Exact(Integer::from(120)),
795        };
796        factorial
797            .format(
798                &mut acc,
799                false,
800                false,
801                &TOO_BIG_NUMBER,
802                &consts,
803                &consts.locales.get("en").unwrap().format(),
804            )
805            .unwrap();
806        assert_eq!(acc, "Factorial of 5 is 120 \n\n");
807
808        let mut acc = String::new();
809        let factorial = Calculation {
810            value: 5.into(),
811            steps: vec![(0, false)],
812            result: CalculationResult::Exact(Integer::from(120)),
813        };
814        factorial
815            .format(
816                &mut acc,
817                false,
818                false,
819                &TOO_BIG_NUMBER,
820                &consts,
821                &consts.locales.get("en").unwrap().format(),
822            )
823            .unwrap();
824        assert_eq!(acc, "Subfactorial of 5 is 120 \n\n");
825
826        let mut acc = String::new();
827        let factorial = Calculation {
828            value: 5.into(),
829            steps: vec![(1, false)],
830            result: CalculationResult::Approximate(
831                Float::with_val(FLOAT_PRECISION, Float::parse("1.2").unwrap()).into(),
832                5.into(),
833            ),
834        };
835        factorial
836            .format(
837                &mut acc,
838                false,
839                false,
840                &TOO_BIG_NUMBER,
841                &consts,
842                &consts.locales.get("en").unwrap().format(),
843            )
844            .unwrap();
845        assert_eq!(acc, "Factorial of 5 is approximately 1.2 × 10^5 \n\n");
846
847        let mut acc = String::new();
848        let factorial = Calculation {
849            value: 5.into(),
850            steps: vec![(1, false)],
851            result: CalculationResult::ApproximateDigits(false, 3.into()),
852        };
853        factorial
854            .format(
855                &mut acc,
856                false,
857                false,
858                &TOO_BIG_NUMBER,
859                &consts,
860                &consts.locales.get("en").unwrap().format(),
861            )
862            .unwrap();
863        assert_eq!(acc, "Factorial of 5 has approximately 3 digits \n\n");
864
865        let mut acc = String::new();
866        let factorial = Calculation {
867            value: 5.into(),
868            steps: vec![(1, false)],
869            result: CalculationResult::Exact(Integer::from(120)),
870        };
871        factorial
872            .format(
873                &mut acc,
874                true,
875                false,
876                &TOO_BIG_NUMBER,
877                &consts,
878                &consts.locales.get("en").unwrap().format(),
879            )
880            .unwrap();
881        assert_eq!(acc, "Factorial of 5 is 120 \n\n");
882    }
883}
884
885#[cfg(test)]
886mod test {
887    use std::{str::FromStr, sync::LazyLock};
888
889    use factorion_math::rug::Complete;
890
891    use super::*;
892
893    use crate::recommended::FLOAT_PRECISION;
894    static TOO_BIG_NUMBER: LazyLock<Integer> =
895        LazyLock::new(|| Integer::from_str(&format!("1{}", "0".repeat(9999))).unwrap());
896
897    // NOTE: The factorials here might be wrong, but we don't care, we are just testing the formatting
898
899    #[test]
900    fn test_format_factorial() {
901        let consts = Consts::default();
902        let fact = Calculation {
903            value: 10.into(),
904            steps: vec![(3, false)],
905            result: CalculationResult::Exact(280.into()),
906        };
907        let mut s = String::new();
908        fact.format(
909            &mut s,
910            false,
911            false,
912            &TOO_BIG_NUMBER,
913            &consts,
914            &consts.locales.get("en").unwrap().format(),
915        )
916        .unwrap();
917        assert_eq!(s, "Triple-factorial of 10 is 280 \n\n");
918    }
919    #[test]
920    fn test_format_factorial_exact_of_decimal() {
921        let consts = Consts::default();
922        let fact = Calculation {
923            value: Number::Float(Float::with_val(FLOAT_PRECISION, 0.5).into()),
924            steps: vec![(3, false)],
925            result: CalculationResult::Exact(280.into()),
926        };
927        let mut s = String::new();
928        fact.format(
929            &mut s,
930            false,
931            false,
932            &TOO_BIG_NUMBER,
933            &consts,
934            &consts.locales.get("en").unwrap().format(),
935        )
936        .unwrap();
937        assert_eq!(s, "Triple-factorial of 0.5 is approximately 280 \n\n");
938    }
939    #[test]
940    fn test_format_factorial_force_shorten_small() {
941        let consts = Consts::default();
942        let fact = Calculation {
943            value: 10.into(),
944            steps: vec![(3, false)],
945            result: CalculationResult::Exact(280.into()),
946        };
947        let mut s = String::new();
948        fact.format(
949            &mut s,
950            true,
951            false,
952            &TOO_BIG_NUMBER,
953            &consts,
954            &consts.locales.get("en").unwrap().format(),
955        )
956        .unwrap();
957        assert_eq!(s, "Triple-factorial of 10 is 280 \n\n");
958    }
959    #[test]
960    fn test_format_factorial_force_shorten_large() {
961        let consts = Consts::default();
962        let fact = Calculation {
963            value: 100.into(),
964            steps: vec![(1, false)],
965            result: CalculationResult::Exact(
966                Integer::from_str("232019615953125000000000000000000").unwrap(),
967            ),
968        };
969        let mut s = String::new();
970        fact.format(
971            &mut s,
972            false,
973            false,
974            &TOO_BIG_NUMBER,
975            &consts,
976            &consts.locales.get("en").unwrap().format(),
977        )
978        .unwrap();
979        assert_eq!(
980            s,
981            "Factorial of 100 is 232019615953125000000000000000000 \n\n"
982        );
983    }
984    #[test]
985    fn test_format_factorial_auto_shorten() {
986        let consts = Consts::default();
987        let fact = Calculation {
988            value: 3249.into(),
989            steps: vec![(1,false)],
990            result: CalculationResult::Exact(
991                Integer::from_str("64123376882765521838840963030568127691878727205333658692200854486404915724268122521695176119279253635876611090137291969570276913721864797759577004121543081865516901512445483449601769965060634861857064173938704305418376606356891014609023859758096597956259938348528946750437026172549655426092377089294607836520057856104816993984697675759579496157280331714452191401635250556082973306115574519424960196953201395066132365440977075392087489735146885581823595966673458107135041749084983583726462930633422893526599365244406644257808664472819062579590372326362859263197427382391737724371130194668325697913147795807287917882271125437793075279592752221056089408917956641344121781056494896664298954714463291743622978314854242079926982168325256172879601086193725507405771749789801611825741625380077209528888301112734777086106637653242107578812065387025070985682845983714635115865868052531038040737170581029905537322341939002838113744745962782070030988628668438192063964391415488312555937962867645737183703289987989371752808444472206166983181218698452231772212240017445423758860236449146575513014084114116542491422920779703202877962388772371297148878539228082497149672927873860981295756607109411429871735683677151117763870227460722732815888175758276344884954699572217509595160880510811349033936358665103889507929390456055037630508759624182491412136058522758117862715726418213812122827526330257260872329993280938592007320434494018056858434839424498517707440601396194949605570023576625190771463278168007414358018195714385208103590743168343592988436427551751120123934640886569178657972642734992568217335134536548423867468448461752994160896483162496996197629537563875663545967947035030506174219867102227347745166308776568259737417457622753953177779829173739659562549005900681020920836575654282170728038645671253311902327576757877160190593437037925134089334990083104974051379653937615220306281104735360028696101767109606466502484676624025302461421267416025443536877684785195571046059926349413586237838043863850610251583618438829618642246353724734656122845609571531588284708710081901687161770748138296656576032229319208279032435434327330035540657667361558905445221013396376775953367966087790302411507662731788873698999846238792500590360394500083923341408008981770566937535640769993694293230514231436990415482012055539596871513163008100690298424743718490882019179903258642028365049142613374709689558800856050749214398290563852574062566904927777093160819034619946818734041081848355062039645388238813669985569729968236449074797273410844560761607809842265309788155248298117938165414543689689754240992067831705834383207309250573018855640140957274364918049364842508738871690383100660359882462072065885517245667353800113210423157317762013988734352812105163694758108035856505778854524789188318600594132430921277654972526820920812190785994887939816114878915385423211996897729890266102145491069991647131611614465930571202528403443141981609375073983780241828798986101030035167624885608168623694530984934856402415662119456280967778213695343026782085453754332973412779641743296676142192492849866399186979810426206090031375249707803725234273693273721779240257093247268647749842459507965336971004339619911629224227060334233904444450352505466038312828689977755744971204784911189528493222070017894145493878499832441010771999957866634720057779638435426615168763950876432375766350648344132624416041623318009761058787995614968607413528076499437020919653085121078341947075546317831737787160036257151637941590867306372647047747729689844801136819011517526975033214302293538465503160183447374945622710595033673253137034231320031041035890947260824330728621640030383790059199531556893062561713763583025693789382680375603227866194301270004745201382665157844733507781537231595412109690534099208802055220457258238249940538761563309465648945964188442431661762589082015016756223358648046396366827537498425276338958018446839292802529780142385903309447658806351362744163752044896322012923382835852429065564336560491610071025646451525782856813152304143339115660276089535216189729579966851236899105440783686498435516601131545345163557980985342246336986737955743799192164259513473592703473521185371309681754246866522812455448210758136891890444056252857117200446002038652603259983493405505521897860879586618028713025173570291196046254005672495787117170419665767607647184551353826735583363126537373726390620854105626900247296291639985561481625404296348051054604042180512892657285238147263167051884385297470314430200590079012539964786079859359747123150407661818942489735756835032462952010303051169237940063644470670372188286551571968317499183600768353941744706305961785518398629201507525785967571188931895809109770264983907551256060144219899670118351808815620474425273993244741972143504134827047237929839845492209316520698259428270901257484509899386082594602760813392081897348940617781009158927227690469330327639146118508499255466535663882163793101115885899345523332216762566667486023534622719542192198250458735391090024294254053186440646305309340840685145289223131431157156390489399333752075193525158125680201419183806547205312873264380358849214095835479613319512867197427682723250079990981586869733293245764804577570764831692705888317075918673294669326798053736223321604803330275717540789920865913177228227111643923604665959921096208765542277777829882980225810940866410254096689483571105776785837917708633884075471298045453873223073787369262426626913405098535070631297346400765749139515252242178612533747493270131589184346851060077512732273563896936880596142362061341020737937605198462006142952423931616201569440226926787162077801883794168906567939864710313203688516686488132607069944238278930371283198545637735863991249832218463680910774912311493673518088306563853170521159963238305666024221618323515872866318153226269712890565361382209276094137857215708859605439920538254391240145615109307534437972388439697355227469268959991826344643967606862639207957142695059497774782782862380576527665249011786632721781635858363134217267161265609789721847126531549373639397319541419174824349828634414533913160986280670700117904134971824878639490677063427559640621162799757094469987184056964512589036737188936656494184932005003301076625555129466247988108160104882718140259576746243025950653945267030862681712132414998384138315991964228278130346276982182371619123375659027762342810200791337975076096607162500887202849331840711439619934443487228446573730294798389422723901661778354768525095757656920903185278358954945675520361768231577076750321654682566951617894418024879897723932943778739392625374786945631297844013055183788373235917906391604745846654356151085578611880261515860397623972021392725059655970516681719822949498069366408864396412928494605832710960284204937215373010567096882590065428759248976242854170628853902061231484918006271406155707387649451852150396381227895427254475130432845540997751264574249884576973754475522081887586009543117655192564603663203594121977491966995919938707026254622729082886656923266824175261927609862131917883084745112234024557978747561458733390353402381353061864973111801478933098174668694254024372053350135966105816774315863351432700501507214833910835095241116220945368287364828423032249431110250529198415073098056537298790818802403747860478015395740166511031245261193793854201285682331906071528112005073514650997116494101706639070013374677115821301361236988511929513457351929738018793684759539098410509535113338894579685309152120362751957602730649344150813012563246391457667149097699631546631367291707994927436193366185835774355812730356484690902974319470019544218388669048171395399380611906621586431005917959473642252829970939300283923684023821586277795276767391621510747281802893209607052311085173753725616353413592446675522238914835135290803927878090361225614843018882327106532840756094139114333346621153175254833577042328095480536834801026590432360931424294133543336408702705440236553526213058195627059654976746315636170233701887454392139871178240463495036735780991998499617099173145932919728906603992606395026374552882029156921168342421270810263586384930758466962518032019544198713384832174173447126633137813741748004660781750992387224960402183367639878315847417040125065349322346833085734948541674565230896990919815801676540094611430605654337096768783494147476599630304276589463660992695730097812987784061106253993478908686689107637583574009574525664941872851644555317421340687668414081763994364249671165252652825318436095248164540239487724330276498957490699548343852181838068378612444949106850962864407345130509165857647406496109100001533123176834579856292423765079015513705518869769002090306548513909235083737585930276738943593954668225536658208962591163051195501324651032924378645456520478535714079874404144783894706654731307268880764144813567558473827034967105368425271973138213726718055181321006250745589786136935583735915890517993411416086214277469794370188740010736604373520529352427775875772577651690552630708696044935360500197728514057299685757816479040563926362665221456966339198099627395349937057349473111399655105587183432516687910987518148931239145857422059143761070545360054386871218955184209375241453611589548642653321253873363792347807426924575722280463634222994099258528815002881358362491008896204800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap()
992            ),
993        };
994        let mut s = String::new();
995        fact.format(
996            &mut s,
997            false,
998            false,
999            &TOO_BIG_NUMBER,
1000            &consts,
1001            &consts.locales.get("en").unwrap().format(),
1002        )
1003        .unwrap();
1004        assert_eq!(
1005            s,
1006            "Factorial of 3249 is roughly 6.412337688276552183884096303057 × 10^10000 \n\n"
1007        );
1008    }
1009    #[test]
1010    fn test_format_factorial_chain() {
1011        let consts = Consts::default();
1012        let fact = Calculation {
1013            value: 5.into(),
1014            steps: vec![(3, false), (1, false)],
1015            result: CalculationResult::Exact(3628800.into()),
1016        };
1017        let mut s = String::new();
1018        fact.format(
1019            &mut s,
1020            false,
1021            false,
1022            &TOO_BIG_NUMBER,
1023            &consts,
1024            &consts.locales.get("en").unwrap().format(),
1025        )
1026        .unwrap();
1027        assert_eq!(s, "Factorial of triple-factorial of 5 is 3628800 \n\n");
1028    }
1029    #[test]
1030    fn test_format_factorial_negative() {
1031        let consts = Consts::default();
1032        let fact = Calculation {
1033            value: 0.into(),
1034            steps: vec![(1, true)],
1035            result: CalculationResult::Exact(3628800.into()),
1036        };
1037        let mut s = String::new();
1038        fact.format(
1039            &mut s,
1040            false,
1041            false,
1042            &TOO_BIG_NUMBER,
1043            &consts,
1044            &consts.locales.get("en").unwrap().format(),
1045        )
1046        .unwrap();
1047        assert_eq!(s, "Negative factorial of 0 is 3628800 \n\n");
1048    }
1049    #[test]
1050    fn test_format_approximate_factorial() {
1051        let consts = Consts::default();
1052        let fact = Calculation {
1053            value: 0.into(),
1054            steps: vec![(1, false)],
1055            result: CalculationResult::Approximate(
1056                Float::with_val(FLOAT_PRECISION, Float::parse("2.83947").unwrap()).into(),
1057                10043.into(),
1058            ),
1059        };
1060        let mut s = String::new();
1061        fact.format(
1062            &mut s,
1063            false,
1064            false,
1065            &TOO_BIG_NUMBER,
1066            &consts,
1067            &consts.locales.get("en").unwrap().format(),
1068        )
1069        .unwrap();
1070        assert_eq!(s, "Factorial of 0 is approximately 2.83947 × 10^10043 \n\n");
1071    }
1072    #[test]
1073    fn test_format_approximate_digits_factorial() {
1074        let consts = Consts::default();
1075        let fact = Calculation {
1076            value: 0.into(),
1077            steps: vec![(1, false)],
1078            result: CalculationResult::ApproximateDigits(false, 10043394.into()),
1079        };
1080        let mut s = String::new();
1081        fact.format(
1082            &mut s,
1083            false,
1084            false,
1085            &TOO_BIG_NUMBER,
1086            &consts,
1087            &consts.locales.get("en").unwrap().format(),
1088        )
1089        .unwrap();
1090        assert_eq!(s, "Factorial of 0 has approximately 10043394 digits \n\n");
1091    }
1092    #[test]
1093    fn test_format_complex_infinity_factorial() {
1094        let consts = Consts::default();
1095        let fact = Calculation {
1096            value: 0.into(),
1097            steps: vec![(1, false)],
1098            result: CalculationResult::ComplexInfinity,
1099        };
1100        let mut s = String::new();
1101        fact.format(
1102            &mut s,
1103            false,
1104            false,
1105            &TOO_BIG_NUMBER,
1106            &consts,
1107            &consts.locales.get("en").unwrap().format(),
1108        )
1109        .unwrap();
1110        assert_eq!(s, "Factorial of 0 is ∞\u{0303} \n\n");
1111    }
1112    #[test]
1113    fn test_format_digits_tower() {
1114        let consts = Consts::default();
1115        let fact = Calculation {
1116            value: 0.into(),
1117            steps: vec![(1, false)],
1118            result: CalculationResult::ApproximateDigitsTower(false, false, 9.into(), 10375.into()),
1119        };
1120        let mut s = String::new();
1121        fact.format(
1122            &mut s,
1123            false,
1124            false,
1125            &TOO_BIG_NUMBER,
1126            &consts,
1127            &consts.locales.get("en").unwrap().format(),
1128        )
1129        .unwrap();
1130        assert_eq!(
1131            s,
1132            "Factorial of 0 has on the order of 10^(10\\^10\\^10\\^10\\^10\\^10\\^10\\^10\\^(10375\\)) digits \n\n"
1133        );
1134    }
1135    #[test]
1136    fn test_format_digits_tower_negative() {
1137        let consts = Consts::default();
1138        let fact = Calculation {
1139            value: 0.into(),
1140            steps: vec![(1, false)],
1141            result: CalculationResult::ApproximateDigitsTower(false, true, 9.into(), 10375.into()),
1142        };
1143        let mut s = String::new();
1144        fact.format(
1145            &mut s,
1146            false,
1147            false,
1148            &TOO_BIG_NUMBER,
1149            &consts,
1150            &consts.locales.get("en").unwrap().format(),
1151        )
1152        .unwrap();
1153        assert_eq!(
1154            s,
1155            "Factorial of 0 has on the order of -10^(10\\^10\\^10\\^10\\^10\\^10\\^10\\^10\\^(10375\\)) digits \n\n"
1156        );
1157    }
1158    #[test]
1159    fn test_format_digits_tower_tet() {
1160        let consts = Consts::default();
1161        let fact = Calculation {
1162            value: 0.into(),
1163            steps: vec![(1, false)],
1164            result: CalculationResult::ApproximateDigitsTower(false, false, 9.into(), 10375.into()),
1165        };
1166        let mut s = String::new();
1167        fact.format(
1168            &mut s,
1169            false,
1170            true,
1171            &TOO_BIG_NUMBER,
1172            &consts,
1173            &consts.locales.get("en").unwrap().format(),
1174        )
1175        .unwrap();
1176        assert_eq!(s, "All that of 0 has on the order of ^(10)10 digits \n\n");
1177    }
1178    #[test]
1179    fn test_format_gamma() {
1180        let consts = Consts::default();
1181        let fact = Calculation {
1182            value: Number::Float(
1183                Float::with_val(FLOAT_PRECISION, Float::parse("9.2").unwrap()).into(),
1184            ),
1185            steps: vec![(1, false)],
1186            result: CalculationResult::Float(
1187                Float::with_val(FLOAT_PRECISION, Float::parse("893.83924421").unwrap()).into(),
1188            ),
1189        };
1190        let mut s = String::new();
1191        fact.format(
1192            &mut s,
1193            false,
1194            false,
1195            &TOO_BIG_NUMBER,
1196            &consts,
1197            &consts.locales.get("en").unwrap().format(),
1198        )
1199        .unwrap();
1200        assert_eq!(s, "Factorial of 9.2 is approximately 893.83924421 \n\n");
1201    }
1202    #[test]
1203    fn test_format_gamma_fallback() {
1204        let consts = Consts::default();
1205        let fact = Calculation {
1206            value: Number::Float(Float::with_val(FLOAT_PRECISION, 0).into()),
1207            steps: vec![(1, false)],
1208            result: {
1209                let mut m = Float::with_val(FLOAT_PRECISION, f64::MAX);
1210                m.next_up();
1211                CalculationResult::Float(m.into())
1212            },
1213        };
1214        let mut s = String::new();
1215        fact.format(
1216            &mut s,
1217            false,
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 0 is approximately 1.797693134862315708145274237317 × 10^308 \n\n"
1227        );
1228    }
1229    #[test]
1230    fn test_format_approximate_factorial_shorten() {
1231        let consts = Consts::default();
1232        let fact = Calculation {
1233            value: Number::Exact(
1234                Integer::from_str("2018338437429423744923849374833232131").unwrap(),
1235            ),
1236            steps: vec![(1, false)],
1237            result: CalculationResult::Approximate(
1238                Float::with_val(FLOAT_PRECISION, Float::parse("2.8394792834").unwrap()).into(),
1239                Integer::from_str("10094283492304894983443984102489842984271").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.018338437429423744923849374833 × 10^36 is approximately 2.8394792834 × 10^(1.009428349230489498344398410249 × 10^40) \n\n"
1255        );
1256    }
1257    #[test]
1258    fn test_format_approximate_digits_factorial_shorten() {
1259        let consts = Consts::default();
1260        let fact = Calculation {
1261            value: Number::Exact(
1262                Integer::from_str("2313820948092579283573259490834298719").unwrap(),
1263            ),
1264            steps: vec![(1, false)],
1265            result: CalculationResult::ApproximateDigits(
1266                false,
1267                Integer::from_str("9842371208573508275237815084709374240128347012847").unwrap(),
1268            ),
1269        };
1270        let mut s = String::new();
1271        fact.format(
1272            &mut s,
1273            true,
1274            false,
1275            &TOO_BIG_NUMBER,
1276            &consts,
1277            &consts.locales.get("en").unwrap().format(),
1278        )
1279        .unwrap();
1280        assert_eq!(
1281            s,
1282            "Factorial of roughly 2.313820948092579283573259490834 × 10^36 has approximately 9.842371208573508275237815084709 × 10^48 digits \n\n"
1283        );
1284    }
1285    #[test]
1286    fn test_format_digits_tower_shorten() {
1287        let consts = Consts::default();
1288        let fact = Calculation {
1289            value: Number::Exact(
1290                Integer::from_str("13204814708471087502685784603872164320053271").unwrap(),
1291            ),
1292            steps: vec![(1, false)],
1293            result: CalculationResult::ApproximateDigitsTower(
1294                false,
1295                false,
1296                9.into(),
1297                Integer::from_str("7084327410873502875032857120358730912469148632").unwrap(),
1298            ),
1299        };
1300        let mut s = String::new();
1301        fact.format(
1302            &mut s,
1303            true,
1304            false,
1305            &TOO_BIG_NUMBER,
1306            &consts,
1307            &consts.locales.get("en").unwrap().format(),
1308        )
1309        .unwrap();
1310        assert_eq!(
1311            s,
1312            "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"
1313        );
1314    }
1315    #[test]
1316    fn test_format_huge() {
1317        let consts = Consts::default();
1318        let fact = Calculation {
1319            value: 0.into(),
1320            steps: vec![(1, false)],
1321            result: CalculationResult::Exact({
1322                let mut r = Float::with_val(FLOAT_PRECISION, crate::rug::float::Special::Infinity);
1323                r.next_down();
1324                r.to_integer().unwrap()
1325            }),
1326        };
1327        let mut s = String::new();
1328        fact.format(
1329            &mut s,
1330            false,
1331            false,
1332            &TOO_BIG_NUMBER,
1333            &consts,
1334            &consts.locales.get("en").unwrap().format(),
1335        )
1336        .unwrap();
1337        assert_eq!(
1338            s,
1339            "Factorial of 0 is roughly 2.098578716467387692404358116884 × 10^323228496 \n\n"
1340        );
1341    }
1342
1343    #[test]
1344    fn test_tower_value_with_one_top() {
1345        let consts = Consts::default();
1346        let fact = Calculation {
1347            value: 0.into(),
1348            steps: vec![(1, false)],
1349            result: CalculationResult::ApproximateDigitsTower(false, false, 4.into(), 1.into()),
1350        };
1351        let mut s = String::new();
1352        fact.format(
1353            &mut s,
1354            false,
1355            false,
1356            &TOO_BIG_NUMBER,
1357            &consts,
1358            &consts.locales.get("en").unwrap().format(),
1359        )
1360        .unwrap();
1361        assert_eq!(s, "Factorial of 0 has on the order of ^(4)10 digits \n\n");
1362    }
1363
1364    #[test]
1365    fn test_calculation_is_approximate() {
1366        let c1 = Calculation {
1367            value: 0.into(),
1368            steps: vec![],
1369            result: CalculationResult::Approximate(
1370                Float::with_val(FLOAT_PRECISION, 2.0).into(),
1371                1.into(),
1372            ),
1373        };
1374        assert!(c1.is_approximate());
1375        let c2 = Calculation {
1376            value: 0.into(),
1377            steps: vec![],
1378            result: CalculationResult::Exact(1.into()),
1379        };
1380        assert!(!c2.is_approximate());
1381    }
1382
1383    #[test]
1384    fn test_calculation_is_rounded() {
1385        let c1 = Calculation {
1386            value: Number::Float(Float::with_val(FLOAT_PRECISION, 1.23).into()),
1387            steps: vec![],
1388            result: CalculationResult::Approximate(
1389                Float::with_val(FLOAT_PRECISION, 0.0).into(),
1390                0.into(),
1391            ),
1392        };
1393        assert!(c1.is_rounded());
1394        let c2 = Calculation {
1395            value: Number::Float(Float::with_val(FLOAT_PRECISION, 1.23).into()),
1396            steps: vec![],
1397            result: CalculationResult::Float(Float::with_val(FLOAT_PRECISION, 1.23).into()),
1398        };
1399        assert!(!c2.is_rounded());
1400        let c3 = Calculation {
1401            value: 1.into(),
1402            steps: vec![],
1403            result: CalculationResult::Exact(1.into()),
1404        };
1405        assert!(!c3.is_rounded());
1406    }
1407
1408    #[test]
1409    fn test_is_too_long() {
1410        let small = Calculation {
1411            value: 1.into(),
1412            steps: vec![],
1413            result: CalculationResult::Exact(1.into()),
1414        };
1415        assert!(!small.is_too_long(&TOO_BIG_NUMBER));
1416        let big = Calculation {
1417            value: 1.into(),
1418            steps: vec![],
1419            result: CalculationResult::Exact((*TOO_BIG_NUMBER).clone() + 1),
1420        };
1421        assert!(big.is_too_long(&TOO_BIG_NUMBER));
1422        let fl = Calculation {
1423            value: 1.into(),
1424            steps: vec![],
1425            result: CalculationResult::Float(Float::with_val(FLOAT_PRECISION, 1.0).into()),
1426        };
1427        assert!(!fl.is_too_long(&TOO_BIG_NUMBER));
1428    }
1429
1430    #[test]
1431    fn test_number_decimals_scientific_respected() {
1432        let mut consts = Consts::default();
1433        consts.number_decimals_scientific = 10;
1434        let mut acc = String::new();
1435        CalculationResult::Exact(Integer::u_pow_u(10, 1000).complete() * 498149837492347328u64)
1436            .format(
1437                &mut acc,
1438                &mut false,
1439                true,
1440                false,
1441                false,
1442                &consts,
1443                &locale::NumFormat::V1(&locale::v1::NumFormat { decimal: '.' }),
1444            )
1445            .unwrap();
1446        assert_eq!(acc, "4.9814983749 × 10^1017");
1447        let mut acc = String::new();
1448        CalculationResult::Approximate(
1449            Float::with_val(FLOAT_PRECISION, 4.98149837492347328f64).into(),
1450            1017.into(),
1451        )
1452        .format(
1453            &mut acc,
1454            &mut false,
1455            true,
1456            false,
1457            false,
1458            &consts,
1459            &locale::NumFormat::V1(&locale::v1::NumFormat { decimal: '.' }),
1460        )
1461        .unwrap();
1462        assert_eq!(acc, "4.9814983749 × 10^(1017)");
1463        consts.number_decimals_scientific = 50;
1464        let mut acc = String::new();
1465        CalculationResult::Exact(
1466            Integer::u_pow_u(10, 1000).complete() * 49814983749234732849839849898438493843u128,
1467        )
1468        .format(
1469            &mut acc,
1470            &mut false,
1471            true,
1472            false,
1473            false,
1474            &consts,
1475            &locale::NumFormat::V1(&locale::v1::NumFormat { decimal: '.' }),
1476        )
1477        .unwrap();
1478        assert_eq!(acc, "4.9814983749234732849839849898438493843 × 10^1037");
1479        let mut acc = String::new();
1480        CalculationResult::Approximate(
1481            Float::with_val(
1482                FLOAT_PRECISION,
1483                Float::parse("4.9814983749234732849839849898438493843").unwrap(),
1484            )
1485            .into(),
1486            1037.into(),
1487        )
1488        .format(
1489            &mut acc,
1490            &mut false,
1491            true,
1492            false,
1493            false,
1494            &consts,
1495            &locale::NumFormat::V1(&locale::v1::NumFormat { decimal: '.' }),
1496        )
1497        .unwrap();
1498        assert_eq!(acc, "4.9814983749234732849839849898438493843 × 10^(1037)");
1499    }
1500}