Skip to main content

oxinum_float/
constants.rs

1//! High-precision mathematical constants: pi, e, ln(2).
2//!
3//! These are computed by parsing pre-computed decimal digit strings at
4//! the requested precision (via `DBig::from_str`), rather than running
5//! expensive iterative algorithms at runtime.  The pre-stored strings
6//! contain 200 decimal digits, which is sufficient for most use cases.
7//! For higher precision, callers can use the `dashu-float` API directly.
8
9use crate::elementary::truncate_decimal_str;
10use crate::DBig;
11use std::str::FromStr;
12
13/// 200 decimal digits of pi.
14const PI_200: &str = "3.14159265358979323846264338327950288419716939937510\
1558209749445923078164062862089986280348253421170679\
1682148086513282306647093844609550582231725359408128\
1748111745028410270193852110555964462294895493038196";
18
19/// 200 decimal digits of e (Euler's number).
20const E_200: &str = "2.71828182845904523536028747135266249775724709369995\
2195749669676277240766303535475945713821785251664274\
2227466391932003059921817413596629043572900334295260\
2359563073813232862794349076323382988075319525101901";
24
25/// 200 decimal digits of ln(2).
26const LN2_200: &str = "0.69314718055994530941723212145817656807550013436025\
2752541206800094933936219696947156058633269964186875\
2842001481020570685733685520235758130557032670751635\
2907526908163220817225884781126976816832788376249023";
30
31/// Compute pi to the given number of decimal digits of precision.
32///
33/// The returned `DBig` has at most `precision` significant digits.
34/// If `precision > 200`, the result contains 200 digits (the
35/// pre-stored resolution).
36///
37/// # Examples
38///
39/// ```
40/// use oxinum_float::compute_pi;
41/// let pi = compute_pi(50);
42/// let s = pi.to_string();
43/// assert!(s.starts_with("3.14159265358979"));
44/// ```
45pub fn compute_pi(precision: usize) -> DBig {
46    parse_at_precision(PI_200, precision)
47}
48
49/// Compute Euler's number *e* to the given number of decimal digits.
50///
51/// # Examples
52///
53/// ```
54/// use oxinum_float::compute_e;
55/// let e = compute_e(50);
56/// let s = e.to_string();
57/// assert!(s.starts_with("2.71828182845904"));
58/// ```
59pub fn compute_e(precision: usize) -> DBig {
60    parse_at_precision(E_200, precision)
61}
62
63/// Compute ln(2) to the given number of decimal digits.
64///
65/// # Examples
66///
67/// ```
68/// use oxinum_float::compute_ln2;
69/// let ln2 = compute_ln2(50);
70/// let s = ln2.to_string();
71/// assert!(s.starts_with("0.69314718055994"));
72/// ```
73pub fn compute_ln2(precision: usize) -> DBig {
74    parse_at_precision(LN2_200, precision)
75}
76
77/// Parse a constant string, truncated to `precision` significant digits.
78fn parse_at_precision(src: &str, precision: usize) -> DBig {
79    let prec = precision.clamp(1, 200);
80    let truncated = truncate_decimal_str(src, prec);
81    DBig::from_str(&truncated).expect("pre-stored constant is a valid decimal literal")
82}
83
84// ---------------------------------------------------------------------------
85// Tests
86// ---------------------------------------------------------------------------
87
88#[cfg(test)]
89mod tests {
90    use super::*;
91
92    #[test]
93    fn pi_starts_correctly() {
94        let pi = compute_pi(50);
95        let s = pi.to_string();
96        assert!(s.starts_with("3.14159265358979"), "pi = {s}");
97    }
98
99    #[test]
100    fn e_starts_correctly() {
101        let e = compute_e(50);
102        let s = e.to_string();
103        assert!(s.starts_with("2.71828182845904"), "e = {s}");
104    }
105
106    #[test]
107    fn ln2_starts_correctly() {
108        let ln2 = compute_ln2(50);
109        let s = ln2.to_string();
110        assert!(s.starts_with("0.69314718055994"), "ln2 = {s}");
111    }
112
113    #[test]
114    fn pi_precision_10() {
115        let pi = compute_pi(10);
116        let s = pi.to_string();
117        assert!(s.starts_with("3.141592653"), "pi(10) = {s}");
118    }
119
120    #[test]
121    fn constants_are_nonzero() {
122        assert_ne!(compute_pi(20).to_string(), "0");
123        assert_ne!(compute_e(20).to_string(), "0");
124        assert_ne!(compute_ln2(20).to_string(), "0");
125    }
126}