factorion_lib/
calculation_results.rs

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