Skip to main content

oxinum_float/native/
context.rs

1//! [`FloatContext`] — precision + rounding-mode builder for native `BigFloat`
2//! transcendentals.
3//!
4//! Captures `(precision, rounding)` once so callers avoid repeating them at
5//! every transcendental call site.
6//!
7//! # Design
8//!
9//! The native [`BigFloat`] transcendental methods all take `(prec: u32, mode:
10//! RoundingMode)` as explicit parameters. `FloatContext` is a thin wrapper that
11//! stores these two values and forwards to the methods unchanged — it does not
12//! add guard bits or change any computation.
13//!
14//! # Naming
15//!
16//! The type is named `FloatContext` rather than `Context` to avoid a collision
17//! with `dashu::Context<R>`, which is re-exported in the same crate.
18//!
19//! # Constant methods
20//!
21//! [`FloatContext::pi`], [`FloatContext::e_const`], and [`FloatContext::ln2`]
22//! return `OxiNumResult<BigFloat>` because the underlying constant generators
23//! (`constants::pi`, etc.) are fallible — they may propagate arithmetic errors
24//! from the internal Chudnovsky / binary-splitting computations.
25//!
26//! # Examples
27//!
28//! ```
29//! use oxinum_float::native::{BigFloat, FloatContext, RoundingMode};
30//!
31//! let ctx = FloatContext::new(200);
32//! let two = BigFloat::from_i64(2, 200, RoundingMode::HalfEven);
33//! let ln2 = ctx.ln(&two).expect("ln(2)");
34//! let back = ctx.exp(&ln2).expect("exp(ln(2))");
35//! assert!(!back.is_zero());
36//! ```
37
38use oxinum_core::OxiNumResult;
39
40use super::constants;
41use super::float::{BigFloat, RoundingMode};
42
43/// Precision context for native `BigFloat` computations.
44///
45/// Stores `precision` (bits) and `rounding` together so that a single
46/// `FloatContext` value can be used across multiple transcendental calls
47/// without repeating the parameters.
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49pub struct FloatContext {
50    precision: u32,
51    rounding: RoundingMode,
52}
53
54impl FloatContext {
55    /// Create a context with the given `precision` in bits and
56    /// [`RoundingMode::HalfEven`] rounding.
57    ///
58    /// # Panics
59    ///
60    /// Panics if `precision == 0` (the `BigFloat` precision invariant requires
61    /// `prec > 0`).
62    pub fn new(precision: u32) -> Self {
63        assert!(precision > 0, "FloatContext precision must be > 0");
64        Self {
65            precision,
66            rounding: RoundingMode::HalfEven,
67        }
68    }
69
70    /// Return a new context identical to `self` but with `rounding` replaced.
71    ///
72    /// Uses the builder pattern so callers can chain:
73    ///
74    /// ```
75    /// use oxinum_float::native::{FloatContext, RoundingMode};
76    /// let ctx = FloatContext::new(128).with_rounding(RoundingMode::ToInf);
77    /// assert_eq!(ctx.rounding(), RoundingMode::ToInf);
78    /// ```
79    #[must_use]
80    pub fn with_rounding(self, mode: RoundingMode) -> Self {
81        Self {
82            rounding: mode,
83            ..self
84        }
85    }
86
87    /// Returns the precision (bits) stored in this context.
88    pub fn precision(&self) -> u32 {
89        self.precision
90    }
91
92    /// Returns the rounding mode stored in this context.
93    pub fn rounding(&self) -> RoundingMode {
94        self.rounding
95    }
96
97    // -----------------------------------------------------------------------
98    // Transcendental forwarders
99    // -----------------------------------------------------------------------
100
101    /// Return `sqrt(x)` at the context precision.
102    pub fn sqrt(&self, x: &BigFloat) -> OxiNumResult<BigFloat> {
103        x.sqrt(self.precision, self.rounding)
104    }
105
106    /// Return `e^x` at the context precision.
107    pub fn exp(&self, x: &BigFloat) -> OxiNumResult<BigFloat> {
108        x.exp(self.precision, self.rounding)
109    }
110
111    /// Return `ln(x)` at the context precision.
112    pub fn ln(&self, x: &BigFloat) -> OxiNumResult<BigFloat> {
113        x.ln(self.precision, self.rounding)
114    }
115
116    /// Return `log_base(x)` at the context precision.
117    pub fn log(&self, x: &BigFloat, base: &BigFloat) -> OxiNumResult<BigFloat> {
118        x.log(base, self.precision, self.rounding)
119    }
120
121    /// Return `x^exp` at the context precision.
122    pub fn pow(&self, x: &BigFloat, exp: &BigFloat) -> OxiNumResult<BigFloat> {
123        x.pow(exp, self.precision, self.rounding)
124    }
125
126    /// Return `sin(x)` at the context precision.
127    pub fn sin(&self, x: &BigFloat) -> OxiNumResult<BigFloat> {
128        x.sin(self.precision, self.rounding)
129    }
130
131    /// Return `cos(x)` at the context precision.
132    pub fn cos(&self, x: &BigFloat) -> OxiNumResult<BigFloat> {
133        x.cos(self.precision, self.rounding)
134    }
135
136    /// Return `tan(x)` at the context precision.
137    pub fn tan(&self, x: &BigFloat) -> OxiNumResult<BigFloat> {
138        x.tan(self.precision, self.rounding)
139    }
140
141    /// Return `atan(x)` at the context precision.
142    pub fn atan(&self, x: &BigFloat) -> OxiNumResult<BigFloat> {
143        x.atan(self.precision, self.rounding)
144    }
145
146    /// Return `atan2(y, x)` at the context precision.
147    ///
148    /// `y` is the first argument (`self` in the inherent method sense);
149    /// `x` is the second.
150    pub fn atan2(&self, y: &BigFloat, x: &BigFloat) -> OxiNumResult<BigFloat> {
151        y.atan2(x, self.precision, self.rounding)
152    }
153
154    // -----------------------------------------------------------------------
155    // Mathematical constants
156    // -----------------------------------------------------------------------
157
158    /// Return π at the context precision.
159    pub fn pi(&self) -> OxiNumResult<BigFloat> {
160        constants::pi(self.precision)
161    }
162
163    /// Return e (Euler's number) at the context precision.
164    pub fn e_const(&self) -> OxiNumResult<BigFloat> {
165        constants::e_const(self.precision)
166    }
167
168    /// Return ln 2 at the context precision.
169    pub fn ln2(&self) -> OxiNumResult<BigFloat> {
170        constants::ln2(self.precision)
171    }
172}