Skip to main content

decimal_scaled/types/traits/
transcendental.rs

1// SPDX-FileCopyrightText: 2026 John Moxley
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! The [`DecimalTranscendental`] trait — the width-generic
5//! transcendental + root surface shared by every decimal type.
6//!
7//! Implemented by every width (`D18`, `D38`, `D57`, `D76`,
8//! `D115`, `D153`, `D230`, `D307`, `D462`, `D616`, `D924`, `D1232`).
9//! Each impl is a one-line delegator to the inherent method of the
10//! same name, so the trait costs nothing at runtime — `#[inline]` on
11//! every method lets LLVM erase the trait dispatch.
12//!
13//! Use it for width-generic helpers:
14//!
15//! ```ignore
16//! use decimal_scaled::{DecimalTranscendental, DecimalConstants};
17//! use decimal_scaled::rounding::RoundingMode;
18//!
19//! fn area_of_disc<T>(radius: T) -> T
20//! where
21//!     T: DecimalTranscendental + DecimalConstants
22//!         + Copy + std::ops::Mul<Output = T>,
23//! {
24//!     T::pi() * radius * radius
25//! }
26//! ```
27//!
28//! # Scope
29//!
30//! Every transcendental and root that has an inherent method on every
31//! width is exposed here in its **four-variant** form (where
32//! applicable):
33//!
34//! - `<fn>_strict` — crate-default guard width + crate-default mode
35//! - `<fn>_strict_with(mode)` — crate-default guard, caller mode
36//! - `<fn>_approx(working_digits)` — caller guard, crate-default mode
37//! - `<fn>_approx_with(working_digits, mode)` — both caller-chosen
38//!
39//! Roots (`sqrt` / `cbrt` / `hypot`) only ship the `_strict` /
40//! `_strict_with` pair — the exact-integer-root path is precision-
41//! independent, so there's no `working_digits` parameter to expose.
42//!
43//! # What's NOT on the trait
44//!
45//! - Joint kernels like `sin_cos` / `sinh_cosh` exist only on the
46//!   wide-tier macros and aren't available on D18 / D38. Access
47//!   them via the concrete type.
48//! - Mathematical constants (`pi`, `tau`, `e`, …) live on the
49//!   separate [`DecimalConstants`] trait so callers can opt in to just
50//!   constants without pulling in the full transcendental surface.
51//!
52//! [`DecimalConstants`]: crate::DecimalConstants
53
54use crate::support::rounding::RoundingMode;
55
56/// Width-generic transcendental + root surface shared by every
57/// decimal width. See the module-level docs for the four-variant
58/// matrix convention and the per-method delegation contract.
59pub trait DecimalTranscendental: Sized {
60    // ── Logarithms ─────────────────────────────────────────────
61
62    /// Natural log. See the log/exp implementation module for the
63    /// algorithm.
64    fn ln_strict(self) -> Self;
65    fn ln_strict_with(self, mode: RoundingMode) -> Self;
66    fn ln_approx(self, working_digits: u32) -> Self;
67    fn ln_approx_with(self, working_digits: u32, mode: RoundingMode) -> Self;
68
69    // `log1p(t) = ln(1 + t)`, domain `t > -1`. Present for API parity
70    // and standards conformance; at fixed point it is equivalent to
71    // `ln(1 + t)` at the same scale, not more accurate.
72
73    fn log1p_strict(self) -> Self;
74    fn log1p_strict_with(self, mode: RoundingMode) -> Self;
75    fn log1p_approx(self, working_digits: u32) -> Self;
76    fn log1p_approx_with(self, working_digits: u32, mode: RoundingMode) -> Self;
77
78    // `expm1(x) = e^x - 1`, total over the argument (it tends to `-1` as
79    // `x -> -inf`). Like `log1p` it is not more accurate than the
80    // two-step form at fixed point, but it does reach slightly further:
81    // the `- 1` is applied at the working scale, ahead of the range
82    // check, so it is defined on `x <= ln(1 + MAX)` where `exp` stops at
83    // `ln(MAX)` — a band `ln(1 + 1/MAX)` wide, a few hundredths.
84
85    fn expm1_strict(self) -> Self;
86    fn expm1_strict_with(self, mode: RoundingMode) -> Self;
87    fn expm1_approx(self, working_digits: u32) -> Self;
88    fn expm1_approx_with(self, working_digits: u32, mode: RoundingMode) -> Self;
89
90    /// Log to caller-chosen base.
91    fn log_strict(self, base: Self) -> Self;
92    fn log_strict_with(self, base: Self, mode: RoundingMode) -> Self;
93    fn log_approx(self, base: Self, working_digits: u32) -> Self;
94    fn log_approx_with(self, base: Self, working_digits: u32, mode: RoundingMode) -> Self;
95
96    /// Log base 2.
97    fn log2_strict(self) -> Self;
98    fn log2_strict_with(self, mode: RoundingMode) -> Self;
99    fn log2_approx(self, working_digits: u32) -> Self;
100    fn log2_approx_with(self, working_digits: u32, mode: RoundingMode) -> Self;
101
102    /// Log base 10.
103    fn log10_strict(self) -> Self;
104    fn log10_strict_with(self, mode: RoundingMode) -> Self;
105    fn log10_approx(self, working_digits: u32) -> Self;
106    fn log10_approx_with(self, working_digits: u32, mode: RoundingMode) -> Self;
107
108    // ── Exponentials ───────────────────────────────────────────
109
110    fn exp_strict(self) -> Self;
111    fn exp_strict_with(self, mode: RoundingMode) -> Self;
112    fn exp_approx(self, working_digits: u32) -> Self;
113    fn exp_approx_with(self, working_digits: u32, mode: RoundingMode) -> Self;
114
115    fn exp2_strict(self) -> Self;
116    fn exp2_strict_with(self, mode: RoundingMode) -> Self;
117    fn exp2_approx(self, working_digits: u32) -> Self;
118    fn exp2_approx_with(self, working_digits: u32, mode: RoundingMode) -> Self;
119
120    // ── Power ──────────────────────────────────────────────────
121
122    fn powf_strict(self, exp: Self) -> Self;
123    fn powf_strict_with(self, exp: Self, mode: RoundingMode) -> Self;
124    fn powf_approx(self, exp: Self, working_digits: u32) -> Self;
125    fn powf_approx_with(self, exp: Self, working_digits: u32, mode: RoundingMode) -> Self;
126
127    // ── Roots ──────────────────────────────────────────────────
128    //
129    // No `_approx` siblings — the exact-integer-root path has no
130    // guard-width parameter to expose.
131
132    fn sqrt_strict(self) -> Self;
133    fn sqrt_strict_with(self, mode: RoundingMode) -> Self;
134
135    fn cbrt_strict(self) -> Self;
136    fn cbrt_strict_with(self, mode: RoundingMode) -> Self;
137
138    fn hypot_strict(self, other: Self) -> Self;
139    fn hypot_strict_with(self, other: Self, mode: RoundingMode) -> Self;
140
141    // ── Trig (forward) ─────────────────────────────────────────
142
143    fn sin_strict(self) -> Self;
144    fn sin_strict_with(self, mode: RoundingMode) -> Self;
145    fn sin_approx(self, working_digits: u32) -> Self;
146    fn sin_approx_with(self, working_digits: u32, mode: RoundingMode) -> Self;
147
148    fn cos_strict(self) -> Self;
149    fn cos_strict_with(self, mode: RoundingMode) -> Self;
150    fn cos_approx(self, working_digits: u32) -> Self;
151    fn cos_approx_with(self, working_digits: u32, mode: RoundingMode) -> Self;
152
153    fn tan_strict(self) -> Self;
154    fn tan_strict_with(self, mode: RoundingMode) -> Self;
155    fn tan_approx(self, working_digits: u32) -> Self;
156    fn tan_approx_with(self, working_digits: u32, mode: RoundingMode) -> Self;
157
158    // ── Trig (inverse) ─────────────────────────────────────────
159
160    fn atan_strict(self) -> Self;
161    fn atan_strict_with(self, mode: RoundingMode) -> Self;
162    fn atan_approx(self, working_digits: u32) -> Self;
163    fn atan_approx_with(self, working_digits: u32, mode: RoundingMode) -> Self;
164
165    fn asin_strict(self) -> Self;
166    fn asin_strict_with(self, mode: RoundingMode) -> Self;
167    fn asin_approx(self, working_digits: u32) -> Self;
168    fn asin_approx_with(self, working_digits: u32, mode: RoundingMode) -> Self;
169
170    fn acos_strict(self) -> Self;
171    fn acos_strict_with(self, mode: RoundingMode) -> Self;
172    fn acos_approx(self, working_digits: u32) -> Self;
173    fn acos_approx_with(self, working_digits: u32, mode: RoundingMode) -> Self;
174
175    /// `atan2(self, other)` — matches the f64 convention where
176    /// `self` is `y` and `other` is `x`.
177    fn atan2_strict(self, other: Self) -> Self;
178    fn atan2_strict_with(self, other: Self, mode: RoundingMode) -> Self;
179    fn atan2_approx(self, other: Self, working_digits: u32) -> Self;
180    fn atan2_approx_with(self, other: Self, working_digits: u32, mode: RoundingMode) -> Self;
181
182    // ── Hyperbolic ─────────────────────────────────────────────
183
184    fn sinh_strict(self) -> Self;
185    fn sinh_strict_with(self, mode: RoundingMode) -> Self;
186    fn sinh_approx(self, working_digits: u32) -> Self;
187    fn sinh_approx_with(self, working_digits: u32, mode: RoundingMode) -> Self;
188
189    fn cosh_strict(self) -> Self;
190    fn cosh_strict_with(self, mode: RoundingMode) -> Self;
191    fn cosh_approx(self, working_digits: u32) -> Self;
192    fn cosh_approx_with(self, working_digits: u32, mode: RoundingMode) -> Self;
193
194    fn tanh_strict(self) -> Self;
195    fn tanh_strict_with(self, mode: RoundingMode) -> Self;
196    fn tanh_approx(self, working_digits: u32) -> Self;
197    fn tanh_approx_with(self, working_digits: u32, mode: RoundingMode) -> Self;
198
199    fn asinh_strict(self) -> Self;
200    fn asinh_strict_with(self, mode: RoundingMode) -> Self;
201    fn asinh_approx(self, working_digits: u32) -> Self;
202    fn asinh_approx_with(self, working_digits: u32, mode: RoundingMode) -> Self;
203
204    fn acosh_strict(self) -> Self;
205    fn acosh_strict_with(self, mode: RoundingMode) -> Self;
206    fn acosh_approx(self, working_digits: u32) -> Self;
207    fn acosh_approx_with(self, working_digits: u32, mode: RoundingMode) -> Self;
208
209    fn atanh_strict(self) -> Self;
210    fn atanh_strict_with(self, mode: RoundingMode) -> Self;
211    fn atanh_approx(self, working_digits: u32) -> Self;
212    fn atanh_approx_with(self, working_digits: u32, mode: RoundingMode) -> Self;
213
214    // ── Angle conversion ───────────────────────────────────────
215
216    fn to_degrees_strict(self) -> Self;
217    fn to_degrees_strict_with(self, mode: RoundingMode) -> Self;
218    fn to_degrees_approx(self, working_digits: u32) -> Self;
219    fn to_degrees_approx_with(self, working_digits: u32, mode: RoundingMode) -> Self;
220
221    fn to_radians_strict(self) -> Self;
222    fn to_radians_strict_with(self, mode: RoundingMode) -> Self;
223    fn to_radians_approx(self, working_digits: u32) -> Self;
224    fn to_radians_approx_with(self, working_digits: u32, mode: RoundingMode) -> Self;
225}