Skip to main content

decimal_scaled/
lib.rs

1// SPDX-FileCopyrightText: 2026 John Moxley
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Const-generic base-10 fixed-point decimal types for deterministic arithmetic.
5//!
6//! # Overview
7//!
8//! `decimal-scaled` provides a family of fixed-point decimal types whose stored
9//! integer encodes `actual_value * 10^SCALE`. Decimal literals like `1.1`
10//! round-trip exactly without any binary approximation, and all core arithmetic
11//! is integer-only — identical bit-patterns on every platform.
12//!
13//! # Primary types
14//!
15//! Each width has a `D<digits><const SCALE: u32>` const-generic shape with the
16//! same method surface; pick the narrowest that fits your range. The number on
17//! every `D{N}` type is its nominal precision in decimal digits; the highest
18//! `SCALE` the type accepts is `MAX_SCALE = N - 1`, leaving at least one
19//! integer digit of headroom at every legal scale.
20//!
21//! | Type | Storage | `MAX_SCALE` | Feature gate |
22//! |------|---------|-------------|--------------|
23//! | [`D18<SCALE>`]   | `i64`     |   17 | always on |
24//! | [`D38<SCALE>`]   | `i128`    |   37 | always on |
25#![cfg_attr(any(feature = "d57", feature = "wide"), doc = "| [`D57<SCALE>`]   | 192-bit   |   56 | `d57` or `wide` |")]
26#![cfg_attr(not(any(feature = "d57", feature = "wide")), doc = "| `D57<SCALE>`   | 192-bit   |   56 | `d57` or `wide` |")]
27#![cfg_attr(any(feature = "d76", feature = "wide"), doc = "| [`D76<SCALE>`]   | 256-bit   |   75 | `d76` or `wide` |")]
28#![cfg_attr(not(any(feature = "d76", feature = "wide")), doc = "| `D76<SCALE>`   | 256-bit   |   75 | `d76` or `wide` |")]
29#![cfg_attr(any(feature = "d115", feature = "wide"), doc = "| [`D115<SCALE>`]  | 384-bit   |  114 | `d115` or `wide` |")]
30#![cfg_attr(not(any(feature = "d115", feature = "wide")), doc = "| `D115<SCALE>`  | 384-bit   |  114 | `d115` or `wide` |")]
31#![cfg_attr(any(feature = "d153", feature = "wide"), doc = "| [`D153<SCALE>`]  | 512-bit   |  152 | `d153` or `wide` |")]
32#![cfg_attr(not(any(feature = "d153", feature = "wide")), doc = "| `D153<SCALE>`  | 512-bit   |  152 | `d153` or `wide` |")]
33#![cfg_attr(any(feature = "d230", feature = "wide"), doc = "| [`D230<SCALE>`]  | 768-bit   |  229 | `d230` or `wide` |")]
34#![cfg_attr(not(any(feature = "d230", feature = "wide")), doc = "| `D230<SCALE>`  | 768-bit   |  229 | `d230` or `wide` |")]
35#![cfg_attr(any(feature = "d307", feature = "wide"), doc = "| [`D307<SCALE>`]  | 1024-bit  |  306 | `d307` or `wide` |")]
36#![cfg_attr(not(any(feature = "d307", feature = "wide")), doc = "| `D307<SCALE>`  | 1024-bit  |  306 | `d307` or `wide` |")]
37#![cfg_attr(any(feature = "d462", feature = "x-wide"), doc = "| [`D462<SCALE>`]  | 1536-bit  |  461 | `d462` or `x-wide` |")]
38#![cfg_attr(not(any(feature = "d462", feature = "x-wide")), doc = "| `D462<SCALE>`  | 1536-bit  |  461 | `d462` or `x-wide` |")]
39#![cfg_attr(any(feature = "d616", feature = "x-wide"), doc = "| [`D616<SCALE>`]  | 2048-bit  |  615 | `d616` or `x-wide` |")]
40#![cfg_attr(not(any(feature = "d616", feature = "x-wide")), doc = "| `D616<SCALE>`  | 2048-bit  |  615 | `d616` or `x-wide` |")]
41#![cfg_attr(any(feature = "d924", feature = "xx-wide"), doc = "| [`D924<SCALE>`]  | 3072-bit  |  923 | `d924` or `xx-wide` |")]
42#![cfg_attr(not(any(feature = "d924", feature = "xx-wide")), doc = "| `D924<SCALE>`  | 3072-bit  |  923 | `d924` or `xx-wide` |")]
43#![cfg_attr(any(feature = "d1232", feature = "xx-wide"), doc = "| [`D1232<SCALE>`] | 4096-bit  | 1231 | `d1232` or `xx-wide` |")]
44#![cfg_attr(not(any(feature = "d1232", feature = "xx-wide")), doc = "| `D1232<SCALE>` | 4096-bit  | 1231 | `d1232` or `xx-wide` |")]
45//!
46//! Umbrellas: `wide` enables D57 / D76 / D115 / D153 / D230 / D307;
47//! `x-wide` adds D462 + D616; `xx-wide` adds D924 + D1232. Every
48//! adjacent pair has lossless `.widen()` / fallible `.narrow()`
49//! helpers plus `From` / `TryFrom` impls.
50//!
51//! Concrete scale aliases such as `D38s12 = D38<12>` are emitted for every
52//! supported `SCALE`. `SCALE = MAX_SCALE + 1` (i.e. `SCALE = N` for `D{N}`) is
53//! rejected at compile time: the scale cap fixes `MAX_SCALE = N - 1` so
54//! every legal scale retains at least one integer digit of headroom.
55//!
56//! The width-generic [`Decimal`] trait carries the surface that is identical
57//! across widths (constants, arithmetic operators, sign methods, integer
58//! variants, pow / checked / wrapping / saturating / overflowing, float bridge,
59//! Euclidean / floor / ceil division, etc.). Use it to write helpers that work
60//! across widths; reach for the concrete type for width-specific operations
61//! like `quantize::<TARGET>()` whose const-generic parameter cannot live on a
62//! trait method.
63//!
64//! # Equality and hashing
65//!
66//! Because each logical value has exactly one representation at a fixed scale,
67//! `Hash`, `Eq`, `PartialEq`, `PartialOrd`, and `Ord` are all derived from the
68//! underlying integer storage. Two `Dxx<S>` values compare equal if and only
69//! if their raw bit patterns are identical. This gives predictable behaviour
70//! when decimal values are used as `HashMap` keys, unlike variable-scale
71//! decimal types where `1.10` and `1.1` may hash differently.
72//!
73//! # `num-traits` compatibility
74//!
75//! Every width implements the standard `num-traits` 0.2 surface:
76//! `Zero`, `One`, `Num`, `Bounded`, `Signed`, `FromPrimitive`,
77//! `ToPrimitive`, and the `Checked{Add,Sub,Mul,Div,Rem,Neg}` family
78//! (see [`::num_traits`]). These impls are unconditional (not behind a
79//! feature flag) because generic numeric code in the wider ecosystem
80//! consumes this surface by default.
81//!
82//! # `no_std` support
83//!
84//! The crate compiles with `no_std + alloc` when default features are
85//! disabled. `alloc` is required for `Display::to_string` and
86//! `FromStr::from_str`. Targets without `alloc` are not supported.
87//!
88//! # Feature flags
89//!
90//! - `std` (default): enables the fast implementations of transcendental
91//! functions (trigonometry, logarithms, exponentials, square root, cube
92//! root, float power) that delegate to platform `f64` intrinsics.
93//! - `alloc`: pulled in automatically; required for string formatting and
94//! parsing.
95//! - `serde`: enables `serde_helpers` for serialisation and deserialisation.
96//! - `strict`: enables integer-only implementations of all transcendental
97//! functions. When `strict` is active each function that would otherwise
98//! route through `f64` is instead implemented using integer-only
99//! algorithms. Explicit float-conversion methods (`to_f64`,
100//! `from_f64`, etc.) remain available regardless; they are type
101//! conversions, not mathematical operations. `strict` does not require
102//! `std`; the integer transcendental implementations compile under
103//! `no_std + alloc`.
104
105#![cfg_attr(not(feature = "std"), no_std)]
106#![cfg_attr(feature = "experimental-floats", feature(f16, f128))]
107#![cfg_attr(
108    any(feature = "cross-scale-ops", feature = "exact-scratch-nightly"),
109    feature(generic_const_exprs)
110)]
111#![cfg_attr(
112    any(feature = "cross-scale-ops", feature = "exact-scratch-nightly"),
113    allow(incomplete_features)
114)]
115// ── Clippy allow-list ─────────────────────────────────────────────────
116//
117// These are pedantic lints whose patterns this crate uses
118// intentionally and pervasively. Each is justified inline; allowing
119// them at the crate level is preferable to spraying per-site
120// `#[allow]` attributes or rewriting against the crate's domain.
121#![allow(
122    // Decimal width names overlap with type prefixes; the lint adds no
123    // signal here.
124    clippy::module_name_repetitions,
125    // We use unindented Markdown continuation in module docs.
126    clippy::doc_lazy_continuation,
127    // We routinely place a blank line between a method's `#[cfg]`
128    // attribute and its doc/body for readability.
129    clippy::empty_line_after_outer_attr,
130    // Big-integer arithmetic regularly casts between signed/unsigned
131    // and between widths. The wraps / truncations / sign flips are
132    // intentional — `unsigned_abs` paths, two's-complement tricks,
133    // narrowing the final result back to storage after a widened mul.
134    clippy::cast_possible_truncation,
135    clippy::cast_possible_wrap,
136    clippy::cast_sign_loss,
137    // We prefer `as` casts over `T::from(x)` in arithmetic-heavy
138    // inner loops for readability and to match the surrounding
139    // big-integer idiom.
140    clippy::cast_lossless,
141    // Float bridges (`to_f64`, `to_f32`) are explicitly lossy by
142    // contract. The lint is a tautology here.
143    clippy::cast_precision_loss,
144    // Literals like `1_000_000_000_000` carry the scale visually and
145    // are kept unseparated when they encode `10^SCALE`.
146    clippy::unreadable_literal,
147    // `if cond { panic!(…) }` is the crate's canonical bounds-check
148    // shape; `assert!(…)` would lose the dynamic message.
149    clippy::manual_assert,
150    // `Result<_, ()>` is the only honest error type for `const fn`
151    // digit-validity checks where no allocator is available.
152    clippy::result_unit_err,
153    // `if …; if …` chains read more cleanly than `if … && …` in the
154    // const-fn limb-arithmetic helpers.
155    clippy::collapsible_if,
156    // Big-int / fixed-point inner loops use `i`, `j`, `k`, `n`, `m`
157    // as conventional names. Renaming to `outer_index` etc. hurts
158    // readability without payoff.
159    clippy::similar_names,
160    clippy::many_single_char_names,
161    // Strict-transcendental kernels exceed 100 lines because they
162    // unroll a series-evaluation loop; splitting them just to please
163    // the line-count lint would scatter the algorithm.
164    clippy::too_many_lines,
165    // `#[inline(always)]` is set deliberately on small hot-path
166    // helpers (`apply_rounding`, `panic_or_wrap_*`). The lint
167    // assumes the inliner knows better; here we override on purpose.
168    clippy::inline_always,
169    // Strict-vs-fast comparisons in `tests/` deliberately compare
170    // raw `f64` results bit-for-bit. The lint can't tell test code
171    // from production.
172    clippy::float_cmp,
173    // Some narrow helpers `let result = …; result + 1` are flagged
174    // as let-else candidates; the explicit form is clearer in the
175    // big-int helpers.
176    clippy::manual_let_else,
177    // `format!("{x}") + "y"` is fine when both pieces stay tiny.
178    clippy::format_push_string,
179    // `if-else-if` chains over disjoint conditions sometimes read
180    // more clearly than `match` (especially with `<` / `>=` arms).
181    clippy::comparison_chain,
182    // Macro-emitted methods that return `Self` are wrapped with
183    // `#[must_use]` where it would catch bugs; the lint's
184    // recommendation on tiny constructors is noise.
185    clippy::must_use_candidate,
186    clippy::return_self_not_must_use,
187    // `# Errors` / `# Panics` sections: every public function's
188    // behaviour on error / panic is described in its main doc
189    // paragraph (and matches the pattern of the std-library
190    // primitive it shadows). The lint's per-section requirement
191    // adds boilerplate without information.
192    clippy::missing_errors_doc,
193    clippy::missing_panics_doc,
194    // Doc-comment backticks are added where they matter (type and
195    // function names); the lint flags every identifier-looking
196    // word, including math symbols and abbreviations.
197    clippy::doc_markdown,
198)]
199
200#[cfg(feature = "alloc")]
201extern crate alloc;
202
203// Re-export `tracing` under the crate so the perf-trace cfg-gated
204// `info_span!` calls in macro-emitted modules can reach it via
205// `$crate::tracing::…`. Internal-only — gated by the same feature.
206#[cfg(feature = "perf-trace")]
207#[doc(hidden)]
208pub use ::tracing;
209
210mod algo_x_support;
211mod algos;
212mod consts;
213mod identity;
214mod support;
215mod types;
216#[cfg(feature = "bench-alt")]
217#[doc(hidden)]
218pub mod __bench_internals {
219    #[inline(never)]
220    pub fn mul_slice(lhs: &[u64], rhs: &[u64], out: &mut [u64]) {
221        crate::int::algos::mul::mul_schoolbook::mul_schoolbook(lhs, rhs, out)
222    }
223    /// Truncated-low fixed-width schoolbook multiply (base-2^64),
224    /// `out = (a * b) mod 2^(64*N)`. The kernel the wide-tier exp/powf
225    /// Taylor work-multiply (`Int<N>::wrapping_mul`) routes through.
226    /// Exposed for the `mul_low_u128_ab` pilot microbench.
227    #[inline(never)]
228    pub fn mul_low_u64<const N: usize>(lhs: &[u64; N], rhs: &[u64; N], out: &mut [u64; N]) {
229        crate::int::algos::mul::mul_schoolbook::mul_low_limb::<N, u64>(lhs, rhs, out)
230    }
231    /// u128-limb-packed truncated-low schoolbook multiply (even `N` only):
232    /// bit-identical low `N` limbs to [`mul_low_u64`], computed in `N/2`
233    /// base-2^128 limbs — the `L = u128` monomorphisation of the one
234    /// `mul_low_limb` kernel. Exposed for the `mul_low_u128_ab` `LimbSize`
235    /// microbench (u64 vs u128 of the same generic kernel).
236    #[inline(never)]
237    pub fn mul_low_u128<const N: usize>(lhs: &[u64; N], rhs: &[u64; N], out: &mut [u64; N]) {
238        crate::int::algos::mul::mul_schoolbook::mul_low_limb::<N, u128>(lhs, rhs, out)
239    }
240    /// Per-`N` monomorphic wrappers over the ONE generic full-product
241    /// schoolbook kernel `mul_full_limb::<N, L>` (the production
242    /// `int::policy::mul` Schoolbook arm). Generated by the `mul_full_wrappers!`
243    /// macro below so each width is a concrete monomorphisation — `Limbs<N>:
244    /// ComputeLimbs` is satisfied at the concrete `N`, so the private bound never
245    /// leaks through a generic `pub` signature (a generic export fails to
246    /// compile). Thin wrappers (no per-tier algorithm copy): the `u64` arm is
247    /// `L = u64` (base-2^64), the `u128` arm is `L = u128` (packed, even `N`
248    /// only). Exposed for the `mul_full_ab` full-product LimbSize +
249    /// Karatsuba-crossover microbench.
250    macro_rules! mul_full_wrappers {
251        // u64-only (odd N — u128 packing requires even N)
252        ($u64name:ident, $n:literal) => {
253            #[inline(never)]
254            pub fn $u64name(lhs: &[u64; $n], rhs: &[u64; $n], out: &mut [u64]) {
255                crate::int::algos::mul::mul_schoolbook::mul_full_limb::<$n, u64>(lhs, rhs, out)
256            }
257        };
258        // both u64 + u128 (even N)
259        ($u64name:ident, $u128name:ident, $n:literal) => {
260            #[inline(never)]
261            pub fn $u64name(lhs: &[u64; $n], rhs: &[u64; $n], out: &mut [u64]) {
262                crate::int::algos::mul::mul_schoolbook::mul_full_limb::<$n, u64>(lhs, rhs, out)
263            }
264            #[inline(never)]
265            pub fn $u128name(lhs: &[u64; $n], rhs: &[u64; $n], out: &mut [u64]) {
266                crate::int::algos::mul::mul_schoolbook::mul_full_limb::<$n, u128>(lhs, rhs, out)
267            }
268        };
269    }
270    mul_full_wrappers!(mul_full_u64_2, mul_full_u128_2, 2);
271    mul_full_wrappers!(mul_full_u64_3, 3);
272    mul_full_wrappers!(mul_full_u64_4, mul_full_u128_4, 4);
273    mul_full_wrappers!(mul_full_u64_6, mul_full_u128_6, 6);
274    mul_full_wrappers!(mul_full_u64_8, mul_full_u128_8, 8);
275    mul_full_wrappers!(mul_full_u64_12, mul_full_u128_12, 12);
276    mul_full_wrappers!(mul_full_u64_16, mul_full_u128_16, 16);
277    mul_full_wrappers!(mul_full_u64_24, mul_full_u128_24, 24);
278    mul_full_wrappers!(mul_full_u64_32, mul_full_u128_32, 32);
279    mul_full_wrappers!(mul_full_u64_48, mul_full_u128_48, 48);
280    mul_full_wrappers!(mul_full_u64_64, mul_full_u128_64, 64);
281    mul_full_wrappers!(mul_full_u64_96, mul_full_u128_96, 96);
282    mul_full_wrappers!(mul_full_u64_128, mul_full_u128_128, 128);
283    mul_full_wrappers!(mul_full_u64_192, mul_full_u128_192, 192);
284    mul_full_wrappers!(mul_full_u64_256, mul_full_u128_256, 256);
285    /// `out = (x²) mod 2^(64*N)` via the u64-limb truncated-low symmetric
286    /// square — the kernel the wide-tier exp/powf Smith squaring loop
287    /// (`BigInt::wrapping_sqr_low_u128`) routes through at `L = u64`. Exposed
288    /// for the `sqr_low_u128_ab` pilot microbench.
289    #[inline(never)]
290    pub fn sqr_low_u64<const N: usize>(value: &[u64; N], out: &mut [u64; N]) {
291        crate::int::algos::sqr::sqr_low_limb::sqr_low_limb::<N, u64>(value, out)
292    }
293    /// u128-limb-packed truncated-low symmetric square (even `N` only):
294    /// bit-identical low `N` limbs to [`sqr_low_u64`], computed in `N/2`
295    /// base-2^128 limbs — the `L = u128` monomorphisation of the one
296    /// `sqr_low_limb` kernel. Exposed for the `sqr_low_u128_ab` `LimbSize`
297    /// microbench (u64 vs u128 of the same generic kernel).
298    #[inline(never)]
299    pub fn sqr_low_u128<const N: usize>(value: &[u64; N], out: &mut [u64; N]) {
300        crate::int::algos::sqr::sqr_low_limb::sqr_low_limb::<N, u128>(value, out)
301    }
302    #[inline(never)]
303    pub fn mul_fixed<const L: usize, const D: usize>(
304        lhs: &[u64; L],
305        rhs: &[u64; L],
306        out: &mut [u64; D],
307    ) {
308        crate::int::algos::mul::mul_schoolbook::mul_schoolbook_fixed::<L, D>(lhs, rhs, out)
309    }
310    /// Non-allocating Karatsuba multiply forced to recurse at the given
311    /// `threshold` (rather than the parked production
312    /// `KARATSUBA_THRESHOLD_U64`), so the crossover sweep can measure the
313    /// kernel at sub-threshold widths. `threshold >= 4` (the recursion's
314    /// termination floor). `out` is zeroed by the callee.
315    #[inline(never)]
316    pub fn mul_karatsuba_forced(lhs: &[u64], rhs: &[u64], out: &mut [u64], threshold: usize) {
317        crate::int::algos::mul::mul_karatsuba::mul_karatsuba_forced(lhs, rhs, out, threshold)
318    }
319    /// Per-N monomorphic wrappers over the Limb-generic Karatsuba kernel
320    /// mul_karatsuba_limb::<N, L>. The u64 arm runs the same recursion as
321    /// mul_karatsuba_forced; the u128 arm packs operands into N/2 u128
322    /// limbs and runs the identical split/recombine in u128 space.
323    /// Exposed for the mul_full_ab bench kara_u64 / kara_u128 arms.
324    macro_rules! mul_kara_limb_wrappers {
325        ($u64name:ident, $n:literal) => {
326            #[inline(never)]
327            pub fn $u64name(lhs: &[u64; $n], rhs: &[u64; $n], out: &mut [u64]) {
328                crate::int::algos::mul::mul_karatsuba::mul_karatsuba_limb::<$n, u64>(lhs, rhs, out, $n)
329            }
330        };
331        ($u64name:ident, $u128name:ident, $n:literal) => {
332            #[inline(never)]
333            pub fn $u64name(lhs: &[u64; $n], rhs: &[u64; $n], out: &mut [u64]) {
334                crate::int::algos::mul::mul_karatsuba::mul_karatsuba_limb::<$n, u64>(lhs, rhs, out, $n)
335            }
336            #[inline(never)]
337            pub fn $u128name(lhs: &[u64; $n], rhs: &[u64; $n], out: &mut [u64]) {
338                crate::int::algos::mul::mul_karatsuba::mul_karatsuba_limb::<$n, u128>(lhs, rhs, out, $n)
339            }
340        };
341    }
342    mul_kara_limb_wrappers!(mul_kara_u64_4, mul_kara_u128_4, 4);
343    mul_kara_limb_wrappers!(mul_kara_u64_6, mul_kara_u128_6, 6);
344    mul_kara_limb_wrappers!(mul_kara_u64_8, mul_kara_u128_8, 8);
345    mul_kara_limb_wrappers!(mul_kara_u64_12, mul_kara_u128_12, 12);
346    mul_kara_limb_wrappers!(mul_kara_u64_16, mul_kara_u128_16, 16);
347    mul_kara_limb_wrappers!(mul_kara_u64_24, mul_kara_u128_24, 24);
348    mul_kara_limb_wrappers!(mul_kara_u64_32, mul_kara_u128_32, 32);
349    mul_kara_limb_wrappers!(mul_kara_u64_48, mul_kara_u128_48, 48);
350    mul_kara_limb_wrappers!(mul_kara_u64_64, mul_kara_u128_64, 64);
351    mul_kara_limb_wrappers!(mul_kara_u64_96, mul_kara_u128_96, 96);
352    mul_kara_limb_wrappers!(mul_kara_u64_128, mul_kara_u128_128, 128);
353    mul_kara_limb_wrappers!(mul_kara_u64_192, mul_kara_u128_192, 192);
354    mul_kara_limb_wrappers!(mul_kara_u64_256, mul_kara_u128_256, 256);
355    /// Threshold-taking u128 Karatsuba wrappers for the threshold-sweep bench
356    /// (step-2 tuning): the recursion base width (in u64-limb units) is a
357    /// runtime arg so the bench can find the optimal crossover depth.
358    macro_rules! mul_kara_u128_thresh {
359        ($name:ident, $n:literal) => {
360            #[inline(never)]
361            pub fn $name(lhs: &[u64; $n], rhs: &[u64; $n], out: &mut [u64], threshold: usize) {
362                crate::int::algos::mul::mul_karatsuba::mul_karatsuba_limb::<$n, u128>(lhs, rhs, out, threshold)
363            }
364        };
365    }
366    mul_kara_u128_thresh!(mul_kara_u128_64_t, 64);
367    mul_kara_u128_thresh!(mul_kara_u128_96_t, 96);
368    mul_kara_u128_thresh!(mul_kara_u128_128_t, 128);
369    mul_kara_u128_thresh!(mul_kara_u128_256_t, 256);
370    /// Toom-Cook 3-way multiply exposed for the mul_toom3_ab microbench.
371    /// out must be zeroed by the caller; out.len() >= 2 * a.len().
372    #[inline(never)]
373    pub fn mul_toom3_slice(lhs: &[u64], rhs: &[u64], out: &mut [u64]) {
374        crate::int::algos::mul::mul_toom3::mul_toom3(lhs, rhs, out)
375    }
376    /// Per-N monomorphic wrappers over the Limb-generic Toom-3 kernel
377    /// mul_toom3_limb::<N, L>. The u64 arm runs the value-slice recursion; the
378    /// u128 arm packs operands into N/2 u128 limbs and runs the identical
379    /// eval/interpolate/recombine in u128 space. Exposed for the mul_toom3_ab
380    /// bench toom3_u128 arm (the policy-map's u64-vs-u128 Toom-3 axis).
381    macro_rules! mul_toom3_limb_wrappers {
382        ($u64name:ident, $u128name:ident, $n:literal) => {
383            #[inline(never)]
384            pub fn $u64name(lhs: &[u64; $n], rhs: &[u64; $n], out: &mut [u64]) {
385                crate::int::algos::mul::mul_toom3::mul_toom3_limb::<$n, u64>(lhs, rhs, out)
386            }
387            #[inline(never)]
388            pub fn $u128name(lhs: &[u64; $n], rhs: &[u64; $n], out: &mut [u64]) {
389                crate::int::algos::mul::mul_toom3::mul_toom3_limb::<$n, u128>(lhs, rhs, out)
390            }
391        };
392    }
393    mul_toom3_limb_wrappers!(mul_toom3_u64_24, mul_toom3_u128_24, 24);
394    mul_toom3_limb_wrappers!(mul_toom3_u64_32, mul_toom3_u128_32, 32);
395    mul_toom3_limb_wrappers!(mul_toom3_u64_48, mul_toom3_u128_48, 48);
396    mul_toom3_limb_wrappers!(mul_toom3_u64_64, mul_toom3_u128_64, 64);
397    mul_toom3_limb_wrappers!(mul_toom3_u64_96, mul_toom3_u128_96, 96);
398    mul_toom3_limb_wrappers!(mul_toom3_u64_128, mul_toom3_u128_128, 128);
399    mul_toom3_limb_wrappers!(mul_toom3_u64_192, mul_toom3_u128_192, 192);
400    mul_toom3_limb_wrappers!(mul_toom3_u64_256, mul_toom3_u128_256, 256);
401    /// Division engine candidates exposed for the `div_kernel_ab`
402    /// microbench (the dispatch-seam A/B for the WIDE integer division
403    /// path). Both take little-endian u64 magnitude limb
404    /// slices; `quot` / `rem` are written by the engine.
405    #[inline(never)]
406    pub fn div_knuth_slice(numerator: &[u64], divisor: &[u64], quotient: &mut [u64], remainder: &mut [u64]) {
407        crate::int::algos::div::div_knuth::div_knuth(numerator, divisor, quotient, remainder)
408    }
409    #[inline(never)]
410    pub fn div_dispatch_slice(numerator: &[u64], divisor: &[u64], quotient: &mut [u64], remainder: &mut [u64]) {
411        crate::int::policy::div_rem::dispatch(numerator, divisor, quotient, remainder)
412    }
413    /// Base-2¹²⁸ (u128-limb) Knuth candidate for `div_kernel_ab` — the
414    /// divide side of the `LimbSize` axis, PARKED (not wired into any
415    /// policy). Bit-identical to [`div_knuth_slice`]; A/B measures whether
416    /// the aligned u128 carry-chain beats base-2⁶⁴ despite the 4-mult q̂·v
417    /// product.
418    #[inline(never)]
419    pub fn div_knuth_u128_limb_slice(numerator: &[u64], divisor: &[u64], quotient: &mut [u64], remainder: &mut [u64]) {
420        crate::int::algos::div::div_knuth_u128_limb::div_knuth_u128_limb(numerator, divisor, quotient, remainder)
421    }
422    /// Burnikel-Ziegler chunking engine FORCED on (production engagement
423    /// guard bypassed) so the Knuth-vs-BZ crossover can be timed at
424    /// sub-threshold widths in `div_kernel_ab`.
425    #[inline(never)]
426    pub fn div_bz_forced_slice(numerator: &[u64], divisor: &[u64], quotient: &mut [u64], remainder: &mut [u64]) {
427        crate::int::algos::div::div_burnikel_ziegler_with_knuth::bz_chunk_core_forced(
428            numerator, divisor, quotient, remainder,
429        )
430    }
431    /// `div_rem` single-/double-limb hardware fast-path candidate for
432    /// `div_kernel_ab` — the `Algorithm::Rem` arm. Bit-identical to the other
433    /// engines; A/B measures the small-divisor regime where the const
434    /// `u128 / u64` path is the production routing.
435    #[inline(never)]
436    pub fn div_rem_fast_slice(numerator: &[u64], divisor: &[u64], quotient: &mut [u64], remainder: &mut [u64]) {
437        crate::int::algos::div::div_rem::div_rem(numerator, divisor, quotient, remainder)
438    }
439    /// `div_rem_schoolbook` binary shift-subtract reference baseline for
440    /// `div_kernel_ab` — the `Algorithm::Schoolbook` arm. Bit-identical to the
441    /// other engines; A/B confirms it is the slowest (the never-routed
442    /// baseline) at every shape.
443    #[inline(never)]
444    pub fn div_schoolbook_slice(numerator: &[u64], divisor: &[u64], quotient: &mut [u64], remainder: &mut [u64]) {
445        crate::int::algos::div::div_rem_schoolbook::div_rem_schoolbook(numerator, divisor, quotient, remainder)
446    }
447    /// Integer hypot kernel candidates for the `hypot_ab` microbench:
448    /// the production Pythagoras path (radicand `a²+b²` + Newton slice
449    /// `isqrt` + round) vs the native-u128 narrow fast path. Both
450    /// bit-identical; A/B confirms which is faster per width.
451    #[inline(never)]
452    #[allow(private_bounds)]
453    pub fn hypot_pythagoras<const N: usize>(
454        lhs: crate::int::types::Int<N>,
455        rhs: crate::int::types::Int<N>,
456        mode: crate::RoundingMode,
457    ) -> Option<crate::int::types::Int<N>>
458    where
459        crate::int::types::compute_limbs::Limbs<N>: crate::int::types::compute_limbs::ComputeLimbs,
460    {
461        crate::int::algos::hypot::hypot_pythagoras::hypot_pythagoras::<N>(lhs, rhs, mode)
462    }
463    #[inline(never)]
464    #[allow(private_bounds)]
465    pub fn hypot_u128_fast<const N: usize>(
466        lhs: crate::int::types::Int<N>,
467        rhs: crate::int::types::Int<N>,
468        mode: crate::RoundingMode,
469    ) -> Option<crate::int::types::Int<N>>
470    where
471        crate::int::types::compute_limbs::Limbs<N>: crate::int::types::compute_limbs::ComputeLimbs,
472    {
473        crate::int::algos::hypot::hypot_u128_fast::hypot_u128_fast::<N>(lhs, rhs, mode)
474    }
475
476    /// Remainder algorithm candidates exposed for the `rem_kernel_ab`
477    /// microbench (the dispatch-seam A/B that decides the `rem` policy
478    /// `select` arm per width).
479    #[inline(never)]
480    pub fn rem_native<const N: usize>(
481        lhs: crate::int::types::Int<N>,
482        rhs: crate::int::types::Int<N>,
483    ) -> crate::int::types::Int<N> {
484        crate::int::algos::rem::rem_native::rem_native::<N>(lhs, rhs)
485    }
486    #[inline(never)]
487    pub fn rem_via_div_rem<const N: usize>(
488        lhs: crate::int::types::Int<N>,
489        rhs: crate::int::types::Int<N>,
490    ) -> crate::int::types::Int<N> {
491        crate::int::algos::rem::rem_via_div_rem::rem_via_div_rem::<N>(lhs, rhs)
492    }
493    #[inline(never)]
494    pub fn rem_schoolbook<const N: usize>(
495        lhs: crate::int::types::Int<N>,
496        rhs: crate::int::types::Int<N>,
497    ) -> crate::int::types::Int<N> {
498        crate::int::algos::rem::rem_schoolbook::rem_schoolbook::<N>(lhs, rhs)
499    }
500    /// Width-agnostic small-magnitude hardware-`%` fast path candidate (the
501    /// value-gated single-word fast path; falls
502    /// back to `via_div_rem` for genuinely-wide operands).
503    #[inline(never)]
504    pub fn rem_small_fast<const N: usize>(
505        lhs: crate::int::types::Int<N>,
506        rhs: crate::int::types::Int<N>,
507    ) -> crate::int::types::Int<N> {
508        crate::int::algos::rem::rem_small_fast::rem_small_fast::<N>(lhs, rhs)
509    }
510    /// Direct two's-complement `i128 %` remainder candidate for `N <= 2`
511    /// (skips the sign-magnitude round trip `rem_native` pays).
512    #[inline(never)]
513    pub fn rem_native_direct<const N: usize>(
514        lhs: crate::int::types::Int<N>,
515        rhs: crate::int::types::Int<N>,
516    ) -> crate::int::types::Int<N> {
517        crate::int::algos::rem::rem_native_direct::rem_native_direct::<N>(lhs, rhs)
518    }
519
520    /// Integer `sqr` kernel candidates exposed for the `int_unary_kernel_ab`
521    /// microbench (the dispatch-seam A/B that confirms the `sqr` policy
522    /// routes to `HalfProduct` at every width vs the `Schoolbook` reference).
523    #[inline(never)]
524    pub fn sqr_half_product<const N: usize>(
525        value: crate::int::types::Uint<N>,
526    ) -> crate::int::types::Uint<N> {
527        crate::int::algos::sqr::sqr_half_product::sqr_half_product::<N>(value)
528    }
529    #[inline(never)]
530    pub fn sqr_schoolbook<const N: usize>(
531        value: crate::int::types::Uint<N>,
532    ) -> crate::int::types::Uint<N> {
533        crate::int::algos::sqr::sqr_schoolbook::sqr_schoolbook::<N>(value)
534    }
535
536    /// Integer `pow` kernel candidates exposed for the `int_unary_kernel_ab`
537    /// microbench (confirms `SquareAndMultiply` beats the `Schoolbook`
538    /// repeated-multiply reference at the small fixed exponents `pow` uses).
539    #[inline(never)]
540    pub fn pow_square_and_multiply<const N: usize>(
541        base: crate::int::types::Uint<N>,
542        exp: u32,
543    ) -> crate::int::types::Uint<N> {
544        crate::int::algos::pow::pow_square_and_multiply::pow_square_and_multiply::<N>(base, exp)
545    }
546    #[inline(never)]
547    pub fn pow_schoolbook<const N: usize>(
548        base: crate::int::types::Uint<N>,
549        exp: u32,
550    ) -> crate::int::types::Uint<N> {
551        crate::int::algos::pow::pow_schoolbook::pow_schoolbook::<N>(base, exp)
552    }
553
554    /// Integer `isqrt` kernel candidates (Newton f64-seeded vs the bitwise
555    /// `Schoolbook` reference) over little-endian magnitude limb slices,
556    /// exposed for the `int_unary_kernel_ab` microbench.
557    #[inline(never)]
558    pub fn isqrt_newton_slice(magnitude: &[u64], out: &mut [u64]) {
559        crate::int::algos::isqrt::isqrt_newton::isqrt_newton(magnitude, out)
560    }
561    #[inline(never)]
562    pub fn isqrt_schoolbook_slice(magnitude: &[u64], out: &mut [u64]) {
563        crate::int::algos::isqrt::isqrt_schoolbook::isqrt_schoolbook(magnitude, out)
564    }
565    /// Native hardware integer square root candidate (`u64::isqrt` for
566    /// `N == 1`, `u128::isqrt` for `N == 2`) exposed for the dedicated
567    /// `isqrt_ab` A/B microbench. Const-`N`: the
568    /// [`isqrt_mag_fixed`][m] wrapper routes `N <= 2` to the hardware path
569    /// and `N >= 3` to Newton, so this arm is only *eligible* (single
570    /// hardware instruction, no Newton loop) at `N <= 2`.
571    ///
572    /// [m]: crate::int::algos::isqrt::isqrt_mag_fixed::isqrt_mag_fixed
573    #[inline(never)]
574    pub fn isqrt_native_fixed<const N: usize>(magnitude: &[u64; N], out: &mut [u64; N]) {
575        crate::int::algos::isqrt::isqrt_mag_fixed::isqrt_mag_fixed::<N>(magnitude, out)
576    }
577
578    /// Integer `icbrt` kernel candidates (Newton f64-seeded vs the bitwise
579    /// `Schoolbook` reference) over little-endian magnitude limb slices,
580    /// exposed for the `int_unary_kernel_ab` microbench.
581    #[inline(never)]
582    pub fn icbrt_newton_slice(magnitude: &[u64], out: &mut [u64]) {
583        crate::int::algos::icbrt::icbrt_newton::icbrt_newton(magnitude, out)
584    }
585    #[inline(never)]
586    pub fn icbrt_schoolbook_slice(magnitude: &[u64], out: &mut [u64]) {
587        crate::int::algos::icbrt::icbrt_schoolbook::icbrt_schoolbook(magnitude, out)
588    }
589
590    /// Karatsuba Square Root candidate (`isqrt_karatsuba`) over little-endian
591    /// magnitude limb slices, exposed for the `isqrt_ab` A/B.
592    /// Bit-identical to [`isqrt_newton_slice`]; A/B measures whether the
593    /// `O(log n)` half-width divides beat Newton's full-width-divide-per-iter
594    /// at each width.
595    #[inline(never)]
596    pub fn isqrt_karatsuba_slice(magnitude: &[u64], out: &mut [u64]) {
597        crate::int::algos::isqrt::isqrt_karatsuba::isqrt_karatsuba(magnitude, out)
598    }
599
600    /// Division-free reciprocal-Newton cube-root candidate
601    /// (`icbrt_newton_recip`) over little-endian magnitude limb slices, exposed
602    /// for the `icbrt_ab` A/B. Bit-identical to
603    /// [`icbrt_newton_slice`]; A/B measures whether the multiply-only
604    /// reciprocal iteration beats the shipped divide-per-iteration Newton.
605    #[inline(never)]
606    pub fn icbrt_newton_recip_slice(magnitude: &[u64], out: &mut [u64]) {
607        crate::int::algos::icbrt::icbrt_newton_recip::icbrt_newton_recip(magnitude, out)
608    }
609
610    /// Integer `cube` candidates exposed for the `int_cube_eq_ab`
611    /// A/B: the shipped sqr-then-multiply [`cube_schoolbook`] vs the fused
612    /// product-scanning (comba) [`cube_fused_comba`] candidate. Both generic
613    /// over `N`, both `const fn`, bit-identical low `N` limbs.
614    #[inline(never)]
615    pub fn cube_schoolbook<const N: usize>(
616        value: crate::int::types::Uint<N>,
617    ) -> crate::int::types::Uint<N> {
618        crate::int::algos::cube::cube_schoolbook::cube_schoolbook::<N>(value)
619    }
620    #[inline(never)]
621    pub fn cube_fused_comba<const N: usize>(
622        value: crate::int::types::Uint<N>,
623    ) -> crate::int::types::Uint<N> {
624        crate::int::algos::cube::cube_fused_comba::cube_fused_comba::<N>(value)
625    }
626
627    /// Integer `eq` candidates exposed for the `int_cube_eq_ab`
628    /// A/B: the shipped [`eq_limbwise`] (reuses the comparison kernel) vs the
629    /// [`eq_xor_fold`] candidate (branchless OR-fold of per-limb XORs). Both
630    /// generic over `N`, both `const fn`, bit-identical.
631    #[inline(never)]
632    pub fn eq_limbwise<const N: usize>(
633        lhs: crate::int::types::Int<N>,
634        rhs: crate::int::types::Int<N>,
635    ) -> bool {
636        crate::int::algos::eq::eq_limbwise::eq_limbwise::<N>(lhs, rhs)
637    }
638    #[inline(never)]
639    pub fn eq_xor_fold<const N: usize>(
640        lhs: crate::int::types::Int<N>,
641        rhs: crate::int::types::Int<N>,
642    ) -> bool {
643        crate::int::algos::eq::eq_xor_fold::eq_xor_fold::<N>(lhs, rhs)
644    }
645
646    /// Per-`N` monomorphic wrappers over the two generic `sum_sq` kernels,
647    /// exposed for the `sum_sq_ab` dispatch-seam microbench: `schoolbook`
648    /// (the WIRED kernel — each square via the general `mul_schoolbook(x,x,..)`
649    /// product, ≈ L² limb-mults) vs `comba` (a KEPT alternative forming each
650    /// square with a symmetric product-scanning pass, ≈ L²/2 limb-mults).
651    /// Bit-identical by construction. Each width is a concrete monomorphisation
652    /// so the private `Limbs<N>: ComputeLimbs` bound never leaks through a generic
653    /// `pub` signature (a generic export with that bound fails to compile).
654    macro_rules! sum_sq_wrappers {
655        ($sb:ident, $cb:ident, $n:literal) => {
656            #[inline(never)]
657            pub fn $sb(
658                lhs: crate::int::types::Int<$n>,
659                rhs: crate::int::types::Int<$n>,
660            ) -> Option<crate::int::types::Int<$n>> {
661                crate::int::algos::sum_sq::sum_sq_schoolbook::sum_sq_schoolbook::<$n>(lhs, rhs)
662            }
663            #[inline(never)]
664            pub fn $cb(
665                lhs: crate::int::types::Int<$n>,
666                rhs: crate::int::types::Int<$n>,
667            ) -> Option<crate::int::types::Int<$n>> {
668                crate::int::algos::sum_sq::sum_sq_comba::sum_sq_comba::<$n>(lhs, rhs)
669            }
670        };
671    }
672    sum_sq_wrappers!(sum_sq_sb_n2, sum_sq_cb_n2, 2);
673    sum_sq_wrappers!(sum_sq_sb_n3, sum_sq_cb_n3, 3);
674    sum_sq_wrappers!(sum_sq_sb_n4, sum_sq_cb_n4, 4);
675    sum_sq_wrappers!(sum_sq_sb_n6, sum_sq_cb_n6, 6);
676    sum_sq_wrappers!(sum_sq_sb_n8, sum_sq_cb_n8, 8);
677    sum_sq_wrappers!(sum_sq_sb_n12, sum_sq_cb_n12, 12);
678    sum_sq_wrappers!(sum_sq_sb_n16, sum_sq_cb_n16, 16);
679    sum_sq_wrappers!(sum_sq_sb_n24, sum_sq_cb_n24, 24);
680    sum_sq_wrappers!(sum_sq_sb_n32, sum_sq_cb_n32, 32);
681    sum_sq_wrappers!(sum_sq_sb_n48, sum_sq_cb_n48, 48);
682    sum_sq_wrappers!(sum_sq_sb_n64, sum_sq_cb_n64, 64);
683
684    /// Decimal divide kernels exposed for the `mul_div_native_ab`
685    /// microbench (the dispatch-seam A/B that decided narrow `N == 2`
686    /// should route to the hardware-`i128` `div_native` arm; mul stays on
687    /// the generic `mul_widen_divide` arm at every band).
688    #[inline(never)]
689    pub fn dec_div_native<const N: usize, const SCALE: u32>(
690        lhs: crate::int::types::Int<N>,
691        rhs: crate::int::types::Int<N>,
692        mode: crate::RoundingMode,
693    ) -> crate::int::types::Int<N> {
694        crate::algos::div::div_native::div_native::<N, SCALE>(lhs, rhs, mode)
695    }
696    #[inline(never)]
697    pub fn dec_div_widen_scale_n1(
698        lhs: crate::int::types::Int<1>,
699        rhs: crate::int::types::Int<1>,
700        multiplier: crate::int::types::Int<1>,
701        mode: crate::RoundingMode,
702    ) -> crate::int::types::Int<1> {
703        crate::algos::div::div_widen_scale::div_widen_scale::<1>(lhs, rhs, multiplier, mode)
704    }
705    #[inline(never)]
706    pub fn dec_div_widen_scale_n2(
707        lhs: crate::int::types::Int<2>,
708        rhs: crate::int::types::Int<2>,
709        multiplier: crate::int::types::Int<2>,
710        mode: crate::RoundingMode,
711    ) -> crate::int::types::Int<2> {
712        crate::algos::div::div_widen_scale::div_widen_scale::<2>(lhs, rhs, multiplier, mode)
713    }
714    /// Decimal multiply kernels exposed for the `mul_div_native_ab`
715    /// microbench (the narrow native-vs-widen mul A/B at the dispatch seam).
716    #[inline(never)]
717    pub fn dec_mul_native<const N: usize, const SCALE: u32>(
718        lhs: crate::int::types::Int<N>,
719        rhs: crate::int::types::Int<N>,
720        mode: crate::RoundingMode,
721    ) -> crate::int::types::Int<N> {
722        crate::algos::mul::mul_native::mul_native::<N, SCALE>(lhs, rhs, mode)
723    }
724    #[inline(never)]
725    pub fn dec_mul_widen_divide_n1<const SCALE: u32>(
726        lhs: crate::int::types::Int<1>,
727        rhs: crate::int::types::Int<1>,
728        mode: crate::RoundingMode,
729    ) -> crate::int::types::Int<1> {
730        crate::algos::mul::mul_widen_divide::mul_widen_divide::<1, SCALE>(lhs, rhs, mode)
731    }
732    #[inline(never)]
733    pub fn dec_mul_widen_divide_n2<const SCALE: u32>(
734        lhs: crate::int::types::Int<2>,
735        rhs: crate::int::types::Int<2>,
736        mode: crate::RoundingMode,
737    ) -> crate::int::types::Int<2> {
738        crate::algos::mul::mul_widen_divide::mul_widen_divide::<2, SCALE>(lhs, rhs, mode)
739    }
740    /// Generic-`N` decimal widen-then-divide multiply, exposed so the
741    /// wide-tier `÷10^w` rescale (the D76/D115/D153 high-scale `mul`
742    /// cells) can be measured at its real storage
743    /// width and scale.
744    #[inline(never)]
745    #[allow(private_bounds)]
746    pub fn dec_mul_widen_divide<const N: usize, const SCALE: u32>(
747        lhs: crate::int::types::Int<N>,
748        rhs: crate::int::types::Int<N>,
749        mode: crate::RoundingMode,
750    ) -> crate::int::types::Int<N>
751    where
752        crate::int::types::compute_limbs::Limbs<N>: crate::int::types::compute_limbs::ComputeLimbs,
753    {
754        crate::algos::mul::mul_widen_divide::mul_widen_divide::<N, SCALE>(lhs, rhs, mode)
755    }
756    /// Decimal remainder kernels exposed for the `rem_kernel_ab` microbench
757    /// (the narrow native-vs-int-layer decimal rem A/B at the dispatch seam).
758    #[inline(never)]
759    #[allow(private_bounds)]
760    pub fn dec_rem_int_layer<const N: usize>(
761        lhs: crate::int::types::Int<N>,
762        rhs: crate::int::types::Int<N>,
763    ) -> crate::int::types::Int<N>
764    where
765        crate::int::types::compute_limbs::Limbs<N>: crate::int::types::compute_limbs::ComputeLimbs,
766    {
767        crate::algos::rem::rem_int_layer::rem_int_layer::<N>(lhs, rhs)
768    }
769    /// The pre-fast-path `rem_int_layer`: always the exact-scratch Knuth
770    /// divmod (no single-word `u128 % u128` short-circuit). Exposed so
771    /// `rem_kernel_ab` can A/B the small-operand fast path's win against the
772    /// divmod-only path it now guards, on the scale-0 benchmark shape.
773    #[inline(never)]
774    #[allow(private_bounds)]
775    pub fn dec_rem_int_layer_divmod<const N: usize>(
776        lhs: crate::int::types::Int<N>,
777        rhs: crate::int::types::Int<N>,
778    ) -> crate::int::types::Int<N>
779    where
780        crate::int::types::compute_limbs::Limbs<N>: crate::int::types::compute_limbs::ComputeLimbs,
781    {
782        crate::algos::rem::rem_int_layer::rem_int_layer_divmod::<N>(lhs, rhs)
783    }
784    /// The `Int::wrapping_rem` wide decimal-remainder path (the const
785    /// single-algorithm `div_rem`, whose multi-limb fallback is an
786    /// `O(bit_len)` binary shift-subtract). Exposed so `rem_kernel_ab` can
787    /// A/B it against the operator/Knuth `rem_int_layer`,
788    /// on the live-bench `k * 10^SCALE` shape.
789    #[inline(never)]
790    pub fn int_wrapping_rem_slice<const N: usize>(
791        lhs: crate::int::types::Int<N>,
792        rhs: crate::int::types::Int<N>,
793    ) -> crate::int::types::Int<N> {
794        lhs.wrapping_rem(rhs)
795    }
796    #[inline(never)]
797    pub fn dec_rem_native<const N: usize>(
798        lhs: crate::int::types::Int<N>,
799        rhs: crate::int::types::Int<N>,
800    ) -> crate::int::types::Int<N> {
801        crate::algos::rem::rem_native::rem_native::<N>(lhs, rhs)
802    }
803    /// Root kernels exposed for the `root_kernel_ab` microbench (the
804    /// dispatch-seam A/B for the D57<20> cbrt candidates).
805    /// `sqrt_mg` / `sqrt_newton_slice` are kept as the D38 sqrt
806    /// reference seam (stays on the 256-bit arm; the hot u128 path is
807    /// ~25 ns). `cbrt_*`
808    /// are the D57<20> candidates: the f64-seeded `Int<6>` native arm vs
809    /// the `Int<6>` + int-`icbrt` table-seed arm vs the generic slice.
810    #[inline(never)]
811    pub fn sqrt_mg<const SCALE: u32>(
812        raw: crate::int::types::Int<2>,
813        mode: crate::RoundingMode,
814    ) -> crate::int::types::Int<2> {
815        crate::algos::sqrt::sqrt_mg_divide::sqrt_mg_divide(raw, SCALE, mode)
816    }
817    #[inline(never)]
818    pub fn sqrt_newton_slice<const SCALE: u32>(
819        raw: crate::int::types::Int<2>,
820        mode: crate::RoundingMode,
821    ) -> crate::int::types::Int<2> {
822        crate::algos::sqrt::sqrt_newton::sqrt_newton::<2>(raw, SCALE, mode)
823    }
824    #[cfg(any(feature = "d57", feature = "wide"))]
825    #[inline(never)]
826    pub fn cbrt_native_d57s20(
827        raw: crate::int::types::Int<3>,
828        mode: crate::RoundingMode,
829    ) -> crate::int::types::Int<3> {
830        crate::algos::cbrt::cbrt_native::cbrt_native_d57s20(raw, mode)
831    }
832    /// Candidate D57<20> cube root (full-radicand f64 seed + Newton
833    /// pre-step) for the `root_kernel_ab` A/B against `cbrt_native_d57s20`.
834    #[cfg(any(feature = "d57", feature = "wide"))]
835    #[inline(never)]
836    pub fn cbrt_native_fast_3limb_s20(
837        raw: crate::int::types::Int<3>,
838        mode: crate::RoundingMode,
839    ) -> crate::int::types::Int<3> {
840        crate::algos::cbrt::cbrt_native_fast::cbrt_native_fast_a::<3, 6>(
841            raw,
842            const { crate::int::types::Int::<6>::TEN.pow(40) },
843            mode,
844        )
845    }
846    #[cfg(any(feature = "d57", feature = "wide"))]
847    #[inline(never)]
848    pub fn cbrt_table_seed_d57s20(
849        raw: crate::int::types::Int<3>,
850        mode: crate::RoundingMode,
851    ) -> crate::int::types::Int<3> {
852        crate::algos::cbrt::cbrt_newton_with_table_seed::cbrt_newton_with_table_seed(raw, mode)
853    }
854    #[cfg(any(feature = "d57", feature = "wide"))]
855    #[inline(never)]
856    pub fn cbrt_newton_slice<const SCALE: u32>(
857        raw: crate::int::types::Int<3>,
858        mode: crate::RoundingMode,
859    ) -> crate::int::types::Int<3> {
860        crate::algos::cbrt::cbrt_newton::cbrt_newton::<3>(raw, SCALE, mode)
861    }
862    /// Generic native root candidates over storage `N`, work width `W`,
863    /// and `SCALE` -- exposed so `root_kernel_ab` can A/B the f64-seeded
864    /// tight-`Int<W>` Newton arm against the generic slice at the wide
865    /// tiers (D76 .. D307).
866    #[cfg(any(feature = "d57", feature = "wide"))]
867    #[inline(never)]
868    pub fn sqrt_native_w<const N: usize, const W: usize, const SCALE: u32>(
869        raw: crate::int::types::Int<N>,
870        mode: crate::RoundingMode,
871    ) -> crate::int::types::Int<N> {
872        crate::algos::sqrt::sqrt_native::sqrt_native::<N, W>(
873            raw,
874            const { crate::int::types::Int::<W>::TEN.pow(SCALE) },
875            mode,
876        )
877    }
878    #[cfg(any(feature = "d57", feature = "wide"))]
879    #[inline(never)]
880    #[allow(private_bounds)]
881    pub fn sqrt_newton_slice_n<const N: usize, const SCALE: u32>(
882        raw: crate::int::types::Int<N>,
883        mode: crate::RoundingMode,
884    ) -> crate::int::types::Int<N>
885    where
886        crate::int::types::compute_limbs::Limbs<N>: crate::int::types::compute_limbs::ComputeLimbs,
887    {
888        crate::algos::sqrt::sqrt_newton::sqrt_newton::<N>(raw, SCALE, mode)
889    }
890    #[cfg(any(feature = "d57", feature = "wide"))]
891    #[inline(never)]
892    pub fn cbrt_native_w<const N: usize, const W: usize, const SCALE: u32>(
893        raw: crate::int::types::Int<N>,
894        mode: crate::RoundingMode,
895    ) -> crate::int::types::Int<N> {
896        crate::algos::cbrt::cbrt_native::cbrt_native::<N, W>(
897            raw,
898            const { crate::int::types::Int::<W>::TEN.pow(2 * SCALE) },
899            mode,
900        )
901    }
902    /// `cbrt_native_fast_a` candidate: full-radicand f64 cbrt seed (with
903    /// shipped-seed fallback past the f64 range). The kernel currently routed
904    /// by `policy::cbrt::Native` at every routed cell. Exposed for the wide
905    /// `(N, W, SCALE)` A/B against `cbrt_native_w` and the slice.
906    #[cfg(any(feature = "d57", feature = "wide"))]
907    #[inline(never)]
908    pub fn cbrt_native_fast_a_w<const N: usize, const W: usize, const SCALE: u32>(
909        raw: crate::int::types::Int<N>,
910        mode: crate::RoundingMode,
911    ) -> crate::int::types::Int<N> {
912        crate::algos::cbrt::cbrt_native_fast::cbrt_native_fast_a::<N, W>(
913            raw,
914            const { crate::int::types::Int::<W>::TEN.pow(2 * SCALE) },
915            mode,
916        )
917    }
918    /// `cbrt_native_fast_b` candidate: width-safe top-bits seed with the
919    /// exact `2^(r/3)` residue multiplier and `+1` margin (vs the shipped
920    /// seed's coarse `2^r` + `+2`). Cuts the seed over-shoot from ~2.5x to
921    /// ~1x, so the monotone Newton loop runs fewer divides. Targets the wide
922    /// `bit_length > 1020` cells where `fast_a` falls back to the shipped
923    /// seed (D230_s172, D462_s346, ...). Bit-identical to `cbrt_native`.
924    #[cfg(any(feature = "d57", feature = "wide"))]
925    #[inline(never)]
926    pub fn cbrt_native_fast_b_w<const N: usize, const W: usize, const SCALE: u32>(
927        raw: crate::int::types::Int<N>,
928        mode: crate::RoundingMode,
929    ) -> crate::int::types::Int<N> {
930        crate::algos::cbrt::cbrt_native_fast::cbrt_native_fast_b::<N, W>(
931            raw,
932            const { crate::int::types::Int::<W>::TEN.pow(2 * SCALE) },
933            mode,
934        )
935    }
936    #[cfg(any(feature = "d57", feature = "wide"))]
937    #[inline(never)]
938    #[allow(private_bounds)]
939    pub fn cbrt_newton_slice_n<const N: usize, const SCALE: u32>(
940        raw: crate::int::types::Int<N>,
941        mode: crate::RoundingMode,
942    ) -> crate::int::types::Int<N>
943    where
944        crate::int::types::compute_limbs::Limbs<N>: crate::int::types::compute_limbs::ComputeLimbs,
945    {
946        crate::algos::cbrt::cbrt_newton::cbrt_newton::<N>(raw, SCALE, mode)
947    }
948
949    // ── transcendental Series-vs-Tang dispatch-seam A/B exports ──────────
950    //
951    // The `policy::{exp,ln,trig}` Series-vs-Tang choice is made by hand-tuned
952    // discrete `(N, SCALE)` bands but was never gated by an N-way `compare_all`
953    // at the dispatch seam (the bands were tuned via `benches/lookup/*` kernel-
954    // ISOLATION benches). These exports expose the Series kernel and the exact
955    // production Tang kernel (same `Core`/`M`/`GUARD`/flag params the policy
956    // `tang_routed` passes) at the band cells so `*_series_tang_ab` can A/B them
957    // bit-identity-asserted at the seam, AND probe just-out-of-band scales.
958    // One concrete fn per `(fn, tier)` cell because `Core` is a concrete per-
959    // tier type; SCALE stays a const generic so the same fn covers in-band and
960    // just-out-of-band probes.
961
962    // exp — Series (generic-over-Core `exp_series`).
963    #[cfg(any(feature = "d57", feature = "wide"))]
964    #[inline(never)]
965    pub fn exp_series_d57<const SCALE: u32>(
966        raw: crate::int::types::Int<3>,
967        mode: crate::RoundingMode,
968    ) -> crate::int::types::Int<3> {
969        crate::algos::support::wide_trig_core::exp_series::<crate::types::widths::wide_trig_d57::Core, SCALE>(raw, mode)
970    }
971    #[cfg(any(feature = "d115", feature = "wide"))]
972    #[inline(never)]
973    pub fn exp_series_d115<const SCALE: u32>(
974        raw: crate::int::types::Int<6>,
975        mode: crate::RoundingMode,
976    ) -> crate::int::types::Int<6> {
977        crate::algos::support::wide_trig_core::exp_series::<crate::types::widths::wide_trig_d115::Core, SCALE>(raw, mode)
978    }
979    #[cfg(any(feature = "d153", feature = "wide"))]
980    #[inline(never)]
981    pub fn exp_series_d153<const SCALE: u32>(
982        raw: crate::int::types::Int<8>,
983        mode: crate::RoundingMode,
984    ) -> crate::int::types::Int<8> {
985        crate::algos::support::wide_trig_core::exp_series::<crate::types::widths::wide_trig_d153::Core, SCALE>(raw, mode)
986    }
987    // exp — Tang (production params per `policy::exp::tang_routed`).
988    // D57 covers the FULL scale range 0..=56 through one continuous Tang arm
989    // (gated by `wide_tang_gate` to small `|x|` < 100), split internally into
990    // 0..=44 (M=128,G=8) and 45..=56 (M=512,G=30). Both bands run the
991    // production wide-tier flag shape <true,true,false> = DIRECTED +
992    // EXTERNAL_EXTRA (matching D76/D115/D153/D230) so the seam A/B's
993    // bit-identity wall validates the same kernel that production calls.
994    // Pass the band's M/G as const generics.
995    #[cfg(all(feature = "_wide-support", any(feature = "d57", feature = "wide")))]
996    #[inline(never)]
997    pub fn exp_tang_d57<const SCALE: u32, const M: u32, const G: u32>(
998        raw: crate::int::types::Int<3>,
999        mode: crate::RoundingMode,
1000    ) -> crate::int::types::Int<3> {
1001        crate::algos::exp::exp_tang::exp_tang::<crate::types::widths::wide_trig_d57::Core, SCALE, M, G, true, true, false>(raw, mode)
1002    }
1003    // D115 band 50..=60: M=128, G=8, flags <true,true,false>.
1004    #[cfg(all(feature = "_wide-support", any(feature = "d115", feature = "wide")))]
1005    #[inline(never)]
1006    pub fn exp_tang_d115<const SCALE: u32>(
1007        raw: crate::int::types::Int<6>,
1008        mode: crate::RoundingMode,
1009    ) -> crate::int::types::Int<6> {
1010        crate::algos::exp::exp_tang::exp_tang::<crate::types::widths::wide_trig_d115::Core, SCALE, 128, 8, true, true, false>(raw, mode)
1011    }
1012    // D153 band 70..=82: M=128, G=10, flags <true,false,true>.
1013    #[cfg(all(feature = "_wide-support", any(feature = "d153", feature = "wide")))]
1014    #[inline(never)]
1015    pub fn exp_tang_d153<const SCALE: u32>(
1016        raw: crate::int::types::Int<8>,
1017        mode: crate::RoundingMode,
1018    ) -> crate::int::types::Int<8> {
1019        crate::algos::exp::exp_tang::exp_tang::<crate::types::widths::wide_trig_d153::Core, SCALE, 128, 10, true, false, true>(raw, mode)
1020    }
1021    // D115 / D153 parameterised Tang (M/G const generics, directed +
1022    // external-extra flags <true,true,false> — the production wide shape) so
1023    // the wide A/B can map M/G across the full scale spread at these tiers,
1024    // not just the single fixed band config above.
1025    #[cfg(all(feature = "_wide-support", any(feature = "d115", feature = "wide")))]
1026    #[inline(never)]
1027    pub fn exp_tang_d115_p<const SCALE: u32, const M: u32, const G: u32>(
1028        raw: crate::int::types::Int<6>,
1029        mode: crate::RoundingMode,
1030    ) -> crate::int::types::Int<6> {
1031        crate::algos::exp::exp_tang::exp_tang::<crate::types::widths::wide_trig_d115::Core, SCALE, M, G, true, true, false>(raw, mode)
1032    }
1033    #[cfg(all(feature = "_wide-support", any(feature = "d153", feature = "wide")))]
1034    #[inline(never)]
1035    pub fn exp_tang_d153_p<const SCALE: u32, const M: u32, const G: u32>(
1036        raw: crate::int::types::Int<8>,
1037        mode: crate::RoundingMode,
1038    ) -> crate::int::types::Int<8> {
1039        crate::algos::exp::exp_tang::exp_tang::<crate::types::widths::wide_trig_d153::Core, SCALE, M, G, true, true, false>(raw, mode)
1040    }
1041
1042    // exp — D76 (Int<4>) and D230 (Int<12>): the two wide-buildable tiers
1043    // that had NO A/B export (D76 has no Tang rectangle at all). Series +
1044    // parameterised Tang (M/G const generics, directed + external-extra
1045    // flags <true,true,false> — the production wide-tier shape, valid at the
1046    // max-scale extreme) so the wide A/B (`exp_wide_series_tang_ab`) can map
1047    // them across the full scale spread and assert Tang == Series (validity).
1048    #[cfg(any(feature = "d76", feature = "wide"))]
1049    #[inline(never)]
1050    pub fn exp_series_d76<const SCALE: u32>(raw: crate::int::types::Int<4>, mode: crate::RoundingMode) -> crate::int::types::Int<4> {
1051        crate::algos::support::wide_trig_core::exp_series::<crate::types::widths::wide_trig_d76::Core, SCALE>(raw, mode)
1052    }
1053    #[cfg(all(feature = "_wide-support", any(feature = "d76", feature = "wide")))]
1054    #[inline(never)]
1055    pub fn exp_tang_d76<const SCALE: u32, const M: u32, const G: u32>(raw: crate::int::types::Int<4>, mode: crate::RoundingMode) -> crate::int::types::Int<4> {
1056        crate::algos::exp::exp_tang::exp_tang::<crate::types::widths::wide_trig_d76::Core, SCALE, M, G, true, true, false>(raw, mode)
1057    }
1058    #[cfg(any(feature = "d230", feature = "wide"))]
1059    #[inline(never)]
1060    pub fn exp_series_d230<const SCALE: u32>(raw: crate::int::types::Int<12>, mode: crate::RoundingMode) -> crate::int::types::Int<12> {
1061        crate::algos::support::wide_trig_core::exp_series::<crate::types::widths::wide_trig_d230::Core, SCALE>(raw, mode)
1062    }
1063    #[cfg(all(feature = "_wide-support", any(feature = "d230", feature = "wide")))]
1064    #[inline(never)]
1065    pub fn exp_tang_d230<const SCALE: u32, const M: u32, const G: u32>(raw: crate::int::types::Int<12>, mode: crate::RoundingMode) -> crate::int::types::Int<12> {
1066        crate::algos::exp::exp_tang::exp_tang::<crate::types::widths::wide_trig_d230::Core, SCALE, M, G, true, true, false>(raw, mode)
1067    }
1068
1069    // exp — wide tiers (N = 16/24/32/48/64). Series + parameterised Tang
1070    // (M/G as const generics, single-shot flags <false,false,false>) so the
1071    // wide-tier A/B (`exp_wide_series_tang_ab`) can sweep the table size and
1072    // guard and assert Tang == Series (the validity wall) before timing.
1073    #[cfg(any(feature = "d307", feature = "wide", feature = "x-wide"))]
1074    #[inline(never)]
1075    pub fn exp_series_d307<const SCALE: u32>(raw: crate::int::types::Int<16>, mode: crate::RoundingMode) -> crate::int::types::Int<16> {
1076        crate::algos::support::wide_trig_core::exp_series::<crate::types::widths::wide_trig_d307::Core, SCALE>(raw, mode)
1077    }
1078    #[cfg(all(feature = "_wide-support", any(feature = "d307", feature = "wide", feature = "x-wide")))]
1079    #[inline(never)]
1080    pub fn exp_tang_d307<const SCALE: u32, const M: u32, const G: u32>(raw: crate::int::types::Int<16>, mode: crate::RoundingMode) -> crate::int::types::Int<16> {
1081        crate::algos::exp::exp_tang::exp_tang::<crate::types::widths::wide_trig_d307::Core, SCALE, M, G, true, true, false>(raw, mode)
1082    }
1083    #[cfg(any(feature = "d462", feature = "x-wide"))]
1084    #[inline(never)]
1085    pub fn exp_series_d462<const SCALE: u32>(raw: crate::int::types::Int<24>, mode: crate::RoundingMode) -> crate::int::types::Int<24> {
1086        crate::algos::support::wide_trig_core::exp_series::<crate::types::widths::wide_trig_d462::Core, SCALE>(raw, mode)
1087    }
1088    #[cfg(all(feature = "_wide-support", any(feature = "d462", feature = "x-wide")))]
1089    #[inline(never)]
1090    pub fn exp_tang_d462<const SCALE: u32, const M: u32, const G: u32>(raw: crate::int::types::Int<24>, mode: crate::RoundingMode) -> crate::int::types::Int<24> {
1091        crate::algos::exp::exp_tang::exp_tang::<crate::types::widths::wide_trig_d462::Core, SCALE, M, G, true, true, false>(raw, mode)
1092    }
1093    #[cfg(any(feature = "d616", feature = "x-wide"))]
1094    #[inline(never)]
1095    pub fn exp_series_d616<const SCALE: u32>(raw: crate::int::types::Int<32>, mode: crate::RoundingMode) -> crate::int::types::Int<32> {
1096        crate::algos::support::wide_trig_core::exp_series::<crate::types::widths::wide_trig_d616::Core, SCALE>(raw, mode)
1097    }
1098    #[cfg(all(feature = "_wide-support", any(feature = "d616", feature = "x-wide")))]
1099    #[inline(never)]
1100    pub fn exp_tang_d616<const SCALE: u32, const M: u32, const G: u32>(raw: crate::int::types::Int<32>, mode: crate::RoundingMode) -> crate::int::types::Int<32> {
1101        crate::algos::exp::exp_tang::exp_tang::<crate::types::widths::wide_trig_d616::Core, SCALE, M, G, true, true, false>(raw, mode)
1102    }
1103    #[cfg(any(feature = "d924", feature = "xx-wide"))]
1104    #[inline(never)]
1105    pub fn exp_series_d924<const SCALE: u32>(raw: crate::int::types::Int<48>, mode: crate::RoundingMode) -> crate::int::types::Int<48> {
1106        crate::algos::support::wide_trig_core::exp_series::<crate::types::widths::wide_trig_d924::Core, SCALE>(raw, mode)
1107    }
1108    #[cfg(all(feature = "_wide-support", any(feature = "d924", feature = "xx-wide")))]
1109    #[inline(never)]
1110    pub fn exp_tang_d924<const SCALE: u32, const M: u32, const G: u32>(raw: crate::int::types::Int<48>, mode: crate::RoundingMode) -> crate::int::types::Int<48> {
1111        crate::algos::exp::exp_tang::exp_tang::<crate::types::widths::wide_trig_d924::Core, SCALE, M, G, true, true, false>(raw, mode)
1112    }
1113    #[cfg(any(feature = "d1232", feature = "xx-wide"))]
1114    #[inline(never)]
1115    pub fn exp_series_d1232<const SCALE: u32>(raw: crate::int::types::Int<64>, mode: crate::RoundingMode) -> crate::int::types::Int<64> {
1116        crate::algos::support::wide_trig_core::exp_series::<crate::types::widths::wide_trig_d1232::Core, SCALE>(raw, mode)
1117    }
1118    #[cfg(all(feature = "_wide-support", any(feature = "d1232", feature = "xx-wide")))]
1119    #[inline(never)]
1120    pub fn exp_tang_d1232<const SCALE: u32, const M: u32, const G: u32>(raw: crate::int::types::Int<64>, mode: crate::RoundingMode) -> crate::int::types::Int<64> {
1121        crate::algos::exp::exp_tang::exp_tang::<crate::types::widths::wide_trig_d1232::Core, SCALE, M, G, true, true, false>(raw, mode)
1122    }
1123
1124    // exp — Schoolbook (the `Algorithm::Schoolbook` reference arm of the wide
1125    // `policy::exp` tiers — the naive Maclaurin series in a Fixed intermediate,
1126    // generic over `Core`). Exported per tier so the A/B bench can
1127    // include Schoolbook as a third candidate at every wide cell —
1128    // benching every Algorithm variant, no exceptions.
1129    // Same `(Int<N>, mode)` shape as `exp_series_d*`.
1130    #[cfg(any(feature = "d57", feature = "wide"))]
1131    #[inline(never)]
1132    pub fn exp_schoolbook_d57<const SCALE: u32>(raw: crate::int::types::Int<3>, mode: crate::RoundingMode) -> crate::int::types::Int<3> {
1133        crate::algos::exp::exp_schoolbook::exp_schoolbook::<crate::types::widths::wide_trig_d57::Core, SCALE>(raw, mode)
1134    }
1135    #[cfg(any(feature = "d76", feature = "wide"))]
1136    #[inline(never)]
1137    pub fn exp_schoolbook_d76<const SCALE: u32>(raw: crate::int::types::Int<4>, mode: crate::RoundingMode) -> crate::int::types::Int<4> {
1138        crate::algos::exp::exp_schoolbook::exp_schoolbook::<crate::types::widths::wide_trig_d76::Core, SCALE>(raw, mode)
1139    }
1140    #[cfg(any(feature = "d115", feature = "wide"))]
1141    #[inline(never)]
1142    pub fn exp_schoolbook_d115<const SCALE: u32>(raw: crate::int::types::Int<6>, mode: crate::RoundingMode) -> crate::int::types::Int<6> {
1143        crate::algos::exp::exp_schoolbook::exp_schoolbook::<crate::types::widths::wide_trig_d115::Core, SCALE>(raw, mode)
1144    }
1145    #[cfg(any(feature = "d153", feature = "wide"))]
1146    #[inline(never)]
1147    pub fn exp_schoolbook_d153<const SCALE: u32>(raw: crate::int::types::Int<8>, mode: crate::RoundingMode) -> crate::int::types::Int<8> {
1148        crate::algos::exp::exp_schoolbook::exp_schoolbook::<crate::types::widths::wide_trig_d153::Core, SCALE>(raw, mode)
1149    }
1150    #[cfg(any(feature = "d230", feature = "wide"))]
1151    #[inline(never)]
1152    pub fn exp_schoolbook_d230<const SCALE: u32>(raw: crate::int::types::Int<12>, mode: crate::RoundingMode) -> crate::int::types::Int<12> {
1153        crate::algos::exp::exp_schoolbook::exp_schoolbook::<crate::types::widths::wide_trig_d230::Core, SCALE>(raw, mode)
1154    }
1155    #[cfg(any(feature = "d307", feature = "wide", feature = "x-wide"))]
1156    #[inline(never)]
1157    pub fn exp_schoolbook_d307<const SCALE: u32>(raw: crate::int::types::Int<16>, mode: crate::RoundingMode) -> crate::int::types::Int<16> {
1158        crate::algos::exp::exp_schoolbook::exp_schoolbook::<crate::types::widths::wide_trig_d307::Core, SCALE>(raw, mode)
1159    }
1160    #[cfg(any(feature = "d462", feature = "x-wide"))]
1161    #[inline(never)]
1162    pub fn exp_schoolbook_d462<const SCALE: u32>(raw: crate::int::types::Int<24>, mode: crate::RoundingMode) -> crate::int::types::Int<24> {
1163        crate::algos::exp::exp_schoolbook::exp_schoolbook::<crate::types::widths::wide_trig_d462::Core, SCALE>(raw, mode)
1164    }
1165    #[cfg(any(feature = "d616", feature = "x-wide"))]
1166    #[inline(never)]
1167    pub fn exp_schoolbook_d616<const SCALE: u32>(raw: crate::int::types::Int<32>, mode: crate::RoundingMode) -> crate::int::types::Int<32> {
1168        crate::algos::exp::exp_schoolbook::exp_schoolbook::<crate::types::widths::wide_trig_d616::Core, SCALE>(raw, mode)
1169    }
1170    #[cfg(any(feature = "d924", feature = "xx-wide"))]
1171    #[inline(never)]
1172    pub fn exp_schoolbook_d924<const SCALE: u32>(raw: crate::int::types::Int<48>, mode: crate::RoundingMode) -> crate::int::types::Int<48> {
1173        crate::algos::exp::exp_schoolbook::exp_schoolbook::<crate::types::widths::wide_trig_d924::Core, SCALE>(raw, mode)
1174    }
1175    #[cfg(any(feature = "d1232", feature = "xx-wide"))]
1176    #[inline(never)]
1177    pub fn exp_schoolbook_d1232<const SCALE: u32>(raw: crate::int::types::Int<64>, mode: crate::RoundingMode) -> crate::int::types::Int<64> {
1178        crate::algos::exp::exp_schoolbook::exp_schoolbook::<crate::types::widths::wide_trig_d1232::Core, SCALE>(raw, mode)
1179    }
1180
1181    // ── hyperbolic (sinh/cosh/tanh) — wide-tier Series-baseline vs Tang-
1182    // composed A/B exports. The "schoolbook" surface is the production
1183    // wide-tier kernel `trig::hyper_schoolbook::*_schoolbook` (which composes
1184    // `(e^|x| ± e^-|x|)` over `exp_fixed`, i.e. Series at these tiers per
1185    // `policy::exp::select` → `Algorithm::Series` for N ≥ 24); the
1186    // "tang_compose" surface is `trig::hyper_exp_identity::*_with_tang`
1187    // composed over `exp_tang::tang_exp_fixed` (the working-scale Tang surface
1188    // with `INTERNAL_EXTRA = true` to cover arbitrary `|k|`). The A/B bench
1189    // (`benches/micro/hyper_wide_tang_ab.rs`) compares the two AT THE PRODUCTION
1190    // SEAM to falsify or confirm the audit's "Pattern A → Tang routing" lead at
1191    // D462/D616/D924/D1232.
1192    #[cfg(any(feature = "d462", feature = "x-wide"))]
1193    #[inline(never)]
1194    pub fn sinh_schoolbook_d462<const SCALE: u32>(raw: crate::int::types::Int<24>, mode: crate::RoundingMode) -> crate::int::types::Int<24> {
1195        crate::algos::trig::hyper_schoolbook::sinh_schoolbook::<crate::types::widths::wide_trig_d462::Core, SCALE>(raw, mode)
1196    }
1197    #[cfg(any(feature = "d462", feature = "x-wide"))]
1198    #[inline(never)]
1199    pub fn cosh_schoolbook_d462<const SCALE: u32>(raw: crate::int::types::Int<24>, mode: crate::RoundingMode) -> crate::int::types::Int<24> {
1200        crate::algos::trig::hyper_schoolbook::cosh_schoolbook::<crate::types::widths::wide_trig_d462::Core, SCALE>(raw, mode)
1201    }
1202    #[cfg(any(feature = "d462", feature = "x-wide"))]
1203    #[inline(never)]
1204    pub fn tanh_schoolbook_d462<const SCALE: u32>(raw: crate::int::types::Int<24>, mode: crate::RoundingMode) -> crate::int::types::Int<24> {
1205        crate::algos::trig::hyper_schoolbook::tanh_schoolbook::<crate::types::widths::wide_trig_d462::Core, SCALE>(raw, mode)
1206    }
1207    #[cfg(all(feature = "_wide-support", any(feature = "d462", feature = "x-wide")))]
1208    #[inline(never)]
1209    pub fn sinh_tang_compose_d462<const SCALE: u32, const M: u32, const GUARD: u32>(raw: crate::int::types::Int<24>, mode: crate::RoundingMode) -> crate::int::types::Int<24> {
1210        crate::algos::trig::hyper_exp_identity::sinh_exp_identity_with_tang::<crate::types::widths::wide_trig_d462::Core, SCALE, GUARD, M, true>(raw, mode)
1211    }
1212    #[cfg(all(feature = "_wide-support", any(feature = "d462", feature = "x-wide")))]
1213    #[inline(never)]
1214    pub fn cosh_tang_compose_d462<const SCALE: u32, const M: u32, const GUARD: u32>(raw: crate::int::types::Int<24>, mode: crate::RoundingMode) -> crate::int::types::Int<24> {
1215        crate::algos::trig::hyper_exp_identity::cosh_exp_identity_with_tang::<crate::types::widths::wide_trig_d462::Core, SCALE, GUARD, M, true>(raw, mode)
1216    }
1217    #[cfg(all(feature = "_wide-support", any(feature = "d462", feature = "x-wide")))]
1218    #[inline(never)]
1219    pub fn tanh_tang_compose_d462<const SCALE: u32, const M: u32, const GUARD: u32>(raw: crate::int::types::Int<24>, mode: crate::RoundingMode) -> crate::int::types::Int<24> {
1220        crate::algos::trig::hyper_exp_identity::tanh_exp_identity_with_tang::<crate::types::widths::wide_trig_d462::Core, SCALE, GUARD, M, true>(raw, mode)
1221    }
1222    #[cfg(any(feature = "d616", feature = "x-wide"))]
1223    #[inline(never)]
1224    pub fn sinh_schoolbook_d616<const SCALE: u32>(raw: crate::int::types::Int<32>, mode: crate::RoundingMode) -> crate::int::types::Int<32> {
1225        crate::algos::trig::hyper_schoolbook::sinh_schoolbook::<crate::types::widths::wide_trig_d616::Core, SCALE>(raw, mode)
1226    }
1227    #[cfg(any(feature = "d616", feature = "x-wide"))]
1228    #[inline(never)]
1229    pub fn cosh_schoolbook_d616<const SCALE: u32>(raw: crate::int::types::Int<32>, mode: crate::RoundingMode) -> crate::int::types::Int<32> {
1230        crate::algos::trig::hyper_schoolbook::cosh_schoolbook::<crate::types::widths::wide_trig_d616::Core, SCALE>(raw, mode)
1231    }
1232    #[cfg(any(feature = "d616", feature = "x-wide"))]
1233    #[inline(never)]
1234    pub fn tanh_schoolbook_d616<const SCALE: u32>(raw: crate::int::types::Int<32>, mode: crate::RoundingMode) -> crate::int::types::Int<32> {
1235        crate::algos::trig::hyper_schoolbook::tanh_schoolbook::<crate::types::widths::wide_trig_d616::Core, SCALE>(raw, mode)
1236    }
1237    #[cfg(all(feature = "_wide-support", any(feature = "d616", feature = "x-wide")))]
1238    #[inline(never)]
1239    pub fn sinh_tang_compose_d616<const SCALE: u32, const M: u32, const GUARD: u32>(raw: crate::int::types::Int<32>, mode: crate::RoundingMode) -> crate::int::types::Int<32> {
1240        crate::algos::trig::hyper_exp_identity::sinh_exp_identity_with_tang::<crate::types::widths::wide_trig_d616::Core, SCALE, GUARD, M, true>(raw, mode)
1241    }
1242    #[cfg(all(feature = "_wide-support", any(feature = "d616", feature = "x-wide")))]
1243    #[inline(never)]
1244    pub fn cosh_tang_compose_d616<const SCALE: u32, const M: u32, const GUARD: u32>(raw: crate::int::types::Int<32>, mode: crate::RoundingMode) -> crate::int::types::Int<32> {
1245        crate::algos::trig::hyper_exp_identity::cosh_exp_identity_with_tang::<crate::types::widths::wide_trig_d616::Core, SCALE, GUARD, M, true>(raw, mode)
1246    }
1247    #[cfg(all(feature = "_wide-support", any(feature = "d616", feature = "x-wide")))]
1248    #[inline(never)]
1249    pub fn tanh_tang_compose_d616<const SCALE: u32, const M: u32, const GUARD: u32>(raw: crate::int::types::Int<32>, mode: crate::RoundingMode) -> crate::int::types::Int<32> {
1250        crate::algos::trig::hyper_exp_identity::tanh_exp_identity_with_tang::<crate::types::widths::wide_trig_d616::Core, SCALE, GUARD, M, true>(raw, mode)
1251    }
1252    #[cfg(any(feature = "d924", feature = "xx-wide"))]
1253    #[inline(never)]
1254    pub fn sinh_schoolbook_d924<const SCALE: u32>(raw: crate::int::types::Int<48>, mode: crate::RoundingMode) -> crate::int::types::Int<48> {
1255        crate::algos::trig::hyper_schoolbook::sinh_schoolbook::<crate::types::widths::wide_trig_d924::Core, SCALE>(raw, mode)
1256    }
1257    #[cfg(any(feature = "d924", feature = "xx-wide"))]
1258    #[inline(never)]
1259    pub fn cosh_schoolbook_d924<const SCALE: u32>(raw: crate::int::types::Int<48>, mode: crate::RoundingMode) -> crate::int::types::Int<48> {
1260        crate::algos::trig::hyper_schoolbook::cosh_schoolbook::<crate::types::widths::wide_trig_d924::Core, SCALE>(raw, mode)
1261    }
1262    #[cfg(any(feature = "d924", feature = "xx-wide"))]
1263    #[inline(never)]
1264    pub fn tanh_schoolbook_d924<const SCALE: u32>(raw: crate::int::types::Int<48>, mode: crate::RoundingMode) -> crate::int::types::Int<48> {
1265        crate::algos::trig::hyper_schoolbook::tanh_schoolbook::<crate::types::widths::wide_trig_d924::Core, SCALE>(raw, mode)
1266    }
1267    #[cfg(all(feature = "_wide-support", any(feature = "d924", feature = "xx-wide")))]
1268    #[inline(never)]
1269    pub fn sinh_tang_compose_d924<const SCALE: u32, const M: u32, const GUARD: u32>(raw: crate::int::types::Int<48>, mode: crate::RoundingMode) -> crate::int::types::Int<48> {
1270        crate::algos::trig::hyper_exp_identity::sinh_exp_identity_with_tang::<crate::types::widths::wide_trig_d924::Core, SCALE, GUARD, M, true>(raw, mode)
1271    }
1272    #[cfg(all(feature = "_wide-support", any(feature = "d924", feature = "xx-wide")))]
1273    #[inline(never)]
1274    pub fn cosh_tang_compose_d924<const SCALE: u32, const M: u32, const GUARD: u32>(raw: crate::int::types::Int<48>, mode: crate::RoundingMode) -> crate::int::types::Int<48> {
1275        crate::algos::trig::hyper_exp_identity::cosh_exp_identity_with_tang::<crate::types::widths::wide_trig_d924::Core, SCALE, GUARD, M, true>(raw, mode)
1276    }
1277    #[cfg(all(feature = "_wide-support", any(feature = "d924", feature = "xx-wide")))]
1278    #[inline(never)]
1279    pub fn tanh_tang_compose_d924<const SCALE: u32, const M: u32, const GUARD: u32>(raw: crate::int::types::Int<48>, mode: crate::RoundingMode) -> crate::int::types::Int<48> {
1280        crate::algos::trig::hyper_exp_identity::tanh_exp_identity_with_tang::<crate::types::widths::wide_trig_d924::Core, SCALE, GUARD, M, true>(raw, mode)
1281    }
1282    #[cfg(any(feature = "d1232", feature = "xx-wide"))]
1283    #[inline(never)]
1284    pub fn sinh_schoolbook_d1232<const SCALE: u32>(raw: crate::int::types::Int<64>, mode: crate::RoundingMode) -> crate::int::types::Int<64> {
1285        crate::algos::trig::hyper_schoolbook::sinh_schoolbook::<crate::types::widths::wide_trig_d1232::Core, SCALE>(raw, mode)
1286    }
1287    #[cfg(any(feature = "d1232", feature = "xx-wide"))]
1288    #[inline(never)]
1289    pub fn cosh_schoolbook_d1232<const SCALE: u32>(raw: crate::int::types::Int<64>, mode: crate::RoundingMode) -> crate::int::types::Int<64> {
1290        crate::algos::trig::hyper_schoolbook::cosh_schoolbook::<crate::types::widths::wide_trig_d1232::Core, SCALE>(raw, mode)
1291    }
1292    #[cfg(any(feature = "d1232", feature = "xx-wide"))]
1293    #[inline(never)]
1294    pub fn tanh_schoolbook_d1232<const SCALE: u32>(raw: crate::int::types::Int<64>, mode: crate::RoundingMode) -> crate::int::types::Int<64> {
1295        crate::algos::trig::hyper_schoolbook::tanh_schoolbook::<crate::types::widths::wide_trig_d1232::Core, SCALE>(raw, mode)
1296    }
1297    #[cfg(all(feature = "_wide-support", any(feature = "d1232", feature = "xx-wide")))]
1298    #[inline(never)]
1299    pub fn sinh_tang_compose_d1232<const SCALE: u32, const M: u32, const GUARD: u32>(raw: crate::int::types::Int<64>, mode: crate::RoundingMode) -> crate::int::types::Int<64> {
1300        crate::algos::trig::hyper_exp_identity::sinh_exp_identity_with_tang::<crate::types::widths::wide_trig_d1232::Core, SCALE, GUARD, M, true>(raw, mode)
1301    }
1302    #[cfg(all(feature = "_wide-support", any(feature = "d1232", feature = "xx-wide")))]
1303    #[inline(never)]
1304    pub fn cosh_tang_compose_d1232<const SCALE: u32, const M: u32, const GUARD: u32>(raw: crate::int::types::Int<64>, mode: crate::RoundingMode) -> crate::int::types::Int<64> {
1305        crate::algos::trig::hyper_exp_identity::cosh_exp_identity_with_tang::<crate::types::widths::wide_trig_d1232::Core, SCALE, GUARD, M, true>(raw, mode)
1306    }
1307    #[cfg(all(feature = "_wide-support", any(feature = "d1232", feature = "xx-wide")))]
1308    #[inline(never)]
1309    pub fn tanh_tang_compose_d1232<const SCALE: u32, const M: u32, const GUARD: u32>(raw: crate::int::types::Int<64>, mode: crate::RoundingMode) -> crate::int::types::Int<64> {
1310        crate::algos::trig::hyper_exp_identity::tanh_exp_identity_with_tang::<crate::types::widths::wide_trig_d1232::Core, SCALE, GUARD, M, true>(raw, mode)
1311    }
1312
1313    // ln — Series (generic-over-Core `ln_series`).
1314    #[cfg(any(feature = "d57", feature = "wide"))]
1315    #[inline(never)]
1316    pub fn ln_series_d57<const SCALE: u32>(
1317        raw: crate::int::types::Int<3>,
1318        mode: crate::RoundingMode,
1319    ) -> crate::int::types::Int<3> {
1320        crate::algos::support::wide_trig_core::ln_series::<crate::types::widths::wide_trig_d57::Core, SCALE>(raw, mode)
1321    }
1322    #[cfg(any(feature = "d115", feature = "wide"))]
1323    #[inline(never)]
1324    pub fn ln_series_d115<const SCALE: u32>(
1325        raw: crate::int::types::Int<6>,
1326        mode: crate::RoundingMode,
1327    ) -> crate::int::types::Int<6> {
1328        crate::algos::support::wide_trig_core::ln_series::<crate::types::widths::wide_trig_d115::Core, SCALE>(raw, mode)
1329    }
1330    #[cfg(any(feature = "d153", feature = "wide"))]
1331    #[inline(never)]
1332    pub fn ln_series_d153<const SCALE: u32>(
1333        raw: crate::int::types::Int<8>,
1334        mode: crate::RoundingMode,
1335    ) -> crate::int::types::Int<8> {
1336        crate::algos::support::wide_trig_core::ln_series::<crate::types::widths::wide_trig_d153::Core, SCALE>(raw, mode)
1337    }
1338    // ln — Tang (production params per `policy::ln::tang_routed`).
1339    // D57 18..=22: <GUARD=8, ITERS=100, false>.
1340    #[cfg(all(feature = "_wide-support", any(feature = "d57", feature = "wide")))]
1341    #[inline(never)]
1342    pub fn ln_tang_d57<const SCALE: u32>(
1343        raw: crate::int::types::Int<3>,
1344        mode: crate::RoundingMode,
1345    ) -> crate::int::types::Int<3> {
1346        crate::algos::ln::ln_tang::ln_tang::<crate::types::widths::wide_trig_d57::Core, SCALE, 8, 100, false, false>(raw, mode)
1347    }
1348    // D115 50..=60: <GUARD=8, ITERS=200, true>.
1349    #[cfg(all(feature = "_wide-support", any(feature = "d115", feature = "wide")))]
1350    #[inline(never)]
1351    pub fn ln_tang_d115<const SCALE: u32>(
1352        raw: crate::int::types::Int<6>,
1353        mode: crate::RoundingMode,
1354    ) -> crate::int::types::Int<6> {
1355        crate::algos::ln::ln_tang::ln_tang::<crate::types::widths::wide_trig_d115::Core, SCALE, 8, 200, true, false>(raw, mode)
1356    }
1357    // D153 70..=82: <GUARD=10, ITERS=200, true>.
1358    #[cfg(all(feature = "_wide-support", any(feature = "d153", feature = "wide")))]
1359    #[inline(never)]
1360    pub fn ln_tang_d153<const SCALE: u32>(
1361        raw: crate::int::types::Int<8>,
1362        mode: crate::RoundingMode,
1363    ) -> crate::int::types::Int<8> {
1364        crate::algos::ln::ln_tang::ln_tang::<crate::types::widths::wide_trig_d153::Core, SCALE, 10, 200, true, false>(raw, mode)
1365    }
1366    // ln — wide tiers (N = 4 / 12 / 16 / 24 / 32 / 48 / 64): Series + Tang
1367    // exports parameterised by (G, CAP) so the wide A/B
1368    // (`benches/micro/ln_wide_series_tang_ab.rs`) can map (G, CAP) across the
1369    // 5-point scale spread per tier and assert Tang == Series (the validity
1370    // wall) before timing — same shape exp uses for the matching A/B. The
1371    // `DIRECTED` flag is fixed `true` (the production directed-Ziv shape every
1372    // wide tier uses); only G and CAP vary at the bench seam.
1373    #[cfg(any(feature = "d76", feature = "wide"))]
1374    #[inline(never)]
1375    pub fn ln_series_d76<const SCALE: u32>(raw: crate::int::types::Int<4>, mode: crate::RoundingMode) -> crate::int::types::Int<4> {
1376        crate::algos::support::wide_trig_core::ln_series::<crate::types::widths::wide_trig_d76::Core, SCALE>(raw, mode)
1377    }
1378    #[cfg(all(feature = "_wide-support", any(feature = "d76", feature = "wide")))]
1379    #[inline(never)]
1380    pub fn ln_tang_d76_p<const SCALE: u32, const G: u32, const CAP: u128>(raw: crate::int::types::Int<4>, mode: crate::RoundingMode) -> crate::int::types::Int<4> {
1381        crate::algos::ln::ln_tang::ln_tang::<crate::types::widths::wide_trig_d76::Core, SCALE, G, CAP, true, false>(raw, mode)
1382    }
1383    #[cfg(any(feature = "d230", feature = "wide"))]
1384    #[inline(never)]
1385    pub fn ln_series_d230<const SCALE: u32>(raw: crate::int::types::Int<12>, mode: crate::RoundingMode) -> crate::int::types::Int<12> {
1386        crate::algos::support::wide_trig_core::ln_series::<crate::types::widths::wide_trig_d230::Core, SCALE>(raw, mode)
1387    }
1388    #[cfg(all(feature = "_wide-support", any(feature = "d230", feature = "wide")))]
1389    #[inline(never)]
1390    pub fn ln_tang_d230_p<const SCALE: u32, const G: u32, const CAP: u128>(raw: crate::int::types::Int<12>, mode: crate::RoundingMode) -> crate::int::types::Int<12> {
1391        crate::algos::ln::ln_tang::ln_tang::<crate::types::widths::wide_trig_d230::Core, SCALE, G, CAP, true, false>(raw, mode)
1392    }
1393    #[cfg(any(feature = "d307", feature = "wide", feature = "x-wide"))]
1394    #[inline(never)]
1395    pub fn ln_series_d307<const SCALE: u32>(raw: crate::int::types::Int<16>, mode: crate::RoundingMode) -> crate::int::types::Int<16> {
1396        crate::algos::support::wide_trig_core::ln_series::<crate::types::widths::wide_trig_d307::Core, SCALE>(raw, mode)
1397    }
1398    #[cfg(all(feature = "_wide-support", any(feature = "d307", feature = "wide", feature = "x-wide")))]
1399    #[inline(never)]
1400    pub fn ln_tang_d307_p<const SCALE: u32, const G: u32, const CAP: u128>(raw: crate::int::types::Int<16>, mode: crate::RoundingMode) -> crate::int::types::Int<16> {
1401        crate::algos::ln::ln_tang::ln_tang::<crate::types::widths::wide_trig_d307::Core, SCALE, G, CAP, true, false>(raw, mode)
1402    }
1403    #[cfg(any(feature = "d462", feature = "x-wide"))]
1404    #[inline(never)]
1405    pub fn ln_series_d462<const SCALE: u32>(raw: crate::int::types::Int<24>, mode: crate::RoundingMode) -> crate::int::types::Int<24> {
1406        crate::algos::support::wide_trig_core::ln_series::<crate::types::widths::wide_trig_d462::Core, SCALE>(raw, mode)
1407    }
1408    #[cfg(all(feature = "_wide-support", any(feature = "d462", feature = "x-wide")))]
1409    #[inline(never)]
1410    pub fn ln_tang_d462_p<const SCALE: u32, const G: u32, const CAP: u128>(raw: crate::int::types::Int<24>, mode: crate::RoundingMode) -> crate::int::types::Int<24> {
1411        crate::algos::ln::ln_tang::ln_tang::<crate::types::widths::wide_trig_d462::Core, SCALE, G, CAP, true, false>(raw, mode)
1412    }
1413    #[cfg(any(feature = "d616", feature = "x-wide"))]
1414    #[inline(never)]
1415    pub fn ln_series_d616<const SCALE: u32>(raw: crate::int::types::Int<32>, mode: crate::RoundingMode) -> crate::int::types::Int<32> {
1416        crate::algos::support::wide_trig_core::ln_series::<crate::types::widths::wide_trig_d616::Core, SCALE>(raw, mode)
1417    }
1418    #[cfg(all(feature = "_wide-support", any(feature = "d616", feature = "x-wide")))]
1419    #[inline(never)]
1420    pub fn ln_tang_d616_p<const SCALE: u32, const G: u32, const CAP: u128>(raw: crate::int::types::Int<32>, mode: crate::RoundingMode) -> crate::int::types::Int<32> {
1421        crate::algos::ln::ln_tang::ln_tang::<crate::types::widths::wide_trig_d616::Core, SCALE, G, CAP, true, false>(raw, mode)
1422    }
1423    #[cfg(any(feature = "d924", feature = "xx-wide"))]
1424    #[inline(never)]
1425    pub fn ln_series_d924<const SCALE: u32>(raw: crate::int::types::Int<48>, mode: crate::RoundingMode) -> crate::int::types::Int<48> {
1426        crate::algos::support::wide_trig_core::ln_series::<crate::types::widths::wide_trig_d924::Core, SCALE>(raw, mode)
1427    }
1428    #[cfg(all(feature = "_wide-support", any(feature = "d924", feature = "xx-wide")))]
1429    #[inline(never)]
1430    pub fn ln_tang_d924_p<const SCALE: u32, const G: u32, const CAP: u128>(raw: crate::int::types::Int<48>, mode: crate::RoundingMode) -> crate::int::types::Int<48> {
1431        crate::algos::ln::ln_tang::ln_tang::<crate::types::widths::wide_trig_d924::Core, SCALE, G, CAP, true, false>(raw, mode)
1432    }
1433    #[cfg(any(feature = "d1232", feature = "xx-wide"))]
1434    #[inline(never)]
1435    pub fn ln_series_d1232<const SCALE: u32>(raw: crate::int::types::Int<64>, mode: crate::RoundingMode) -> crate::int::types::Int<64> {
1436        crate::algos::support::wide_trig_core::ln_series::<crate::types::widths::wide_trig_d1232::Core, SCALE>(raw, mode)
1437    }
1438    #[cfg(all(feature = "_wide-support", any(feature = "d1232", feature = "xx-wide")))]
1439    #[inline(never)]
1440    pub fn ln_tang_d1232_p<const SCALE: u32, const G: u32, const CAP: u128>(raw: crate::int::types::Int<64>, mode: crate::RoundingMode) -> crate::int::types::Int<64> {
1441        crate::algos::ln::ln_tang::ln_tang::<crate::types::widths::wide_trig_d1232::Core, SCALE, G, CAP, true, false>(raw, mode)
1442    }
1443
1444    // trig forward (sin) — the only narrow-wide tier with a real Tang wiring
1445    // is D57 (band 44..=56, M=512); tiers 4/6/12/32/48/64 route the Tang select
1446    // arm back to `sin_series` (and `select` never returns Tang there), and
1447    // D153/D307/D462 have their own bespoke impls. D57 is the clean `wide`-
1448    // buildable band edge.
1449    #[cfg(any(feature = "d57", feature = "wide"))]
1450    #[inline(never)]
1451    pub fn sin_series_d57<const SCALE: u32>(
1452        raw: crate::int::types::Int<3>,
1453        mode: crate::RoundingMode,
1454    ) -> crate::int::types::Int<3> {
1455        crate::algos::support::wide_trig_core::sin_series::<crate::types::widths::wide_trig_d57::Core, SCALE>(raw, mode)
1456    }
1457    #[cfg(all(feature = "_wide-support", any(feature = "d57", feature = "wide")))]
1458    #[inline(never)]
1459    pub fn sin_tang_d57<const SCALE: u32>(
1460        raw: crate::int::types::Int<3>,
1461        mode: crate::RoundingMode,
1462    ) -> crate::int::types::Int<3> {
1463        crate::algos::trig::sincos_tang::sin_tang_with_taylor::<crate::types::widths::wide_trig_d57::Core, SCALE, 512>(raw, mode)
1464    }
1465
1466    // D462 forward-trig bench seam — sin/cos/tan/atan Series-vs-narrow A/B
1467    // for the A/B bisection of the (24, 225..=235) band. The "Tang"
1468    // variant at D462 is realised by `sincos_narrow::*_with_taylor` (a
1469    // narrowed-GUARD Taylor reclaim — not actual Tang lookup, see the
1470    // kernel module doc), parameterised by the band GUARD so the bench can
1471    // sweep G. Production wires G=10 for sin/cos/tan and G=12 for atan.
1472    #[cfg(any(feature = "d462", feature = "x-wide"))]
1473    #[inline(never)]
1474    pub fn sin_series_d462<const SCALE: u32>(
1475        raw: crate::int::types::Int<24>,
1476        mode: crate::RoundingMode,
1477    ) -> crate::int::types::Int<24> {
1478        crate::algos::support::wide_trig_core::sin_series::<crate::types::widths::wide_trig_d462::Core, SCALE>(raw, mode)
1479    }
1480    #[cfg(any(feature = "d462", feature = "x-wide"))]
1481    #[inline(never)]
1482    pub fn sin_narrow_d462<const SCALE: u32, const GUARD: u32>(
1483        raw: crate::int::types::Int<24>,
1484        mode: crate::RoundingMode,
1485    ) -> crate::int::types::Int<24> {
1486        crate::algos::trig::sincos_narrow::sin_narrow_with_taylor::<crate::types::widths::wide_trig_d462::Core, SCALE, GUARD>(raw, mode)
1487    }
1488    #[cfg(any(feature = "d462", feature = "x-wide"))]
1489    #[inline(never)]
1490    pub fn cos_series_d462<const SCALE: u32>(
1491        raw: crate::int::types::Int<24>,
1492        mode: crate::RoundingMode,
1493    ) -> crate::int::types::Int<24> {
1494        crate::algos::support::wide_trig_core::cos_series::<crate::types::widths::wide_trig_d462::Core, SCALE>(raw, mode)
1495    }
1496    #[cfg(any(feature = "d462", feature = "x-wide"))]
1497    #[inline(never)]
1498    pub fn cos_narrow_d462<const SCALE: u32, const GUARD: u32>(
1499        raw: crate::int::types::Int<24>,
1500        mode: crate::RoundingMode,
1501    ) -> crate::int::types::Int<24> {
1502        crate::algos::trig::sincos_narrow::cos_narrow_with_taylor::<crate::types::widths::wide_trig_d462::Core, SCALE, GUARD>(raw, mode)
1503    }
1504    #[cfg(any(feature = "d462", feature = "x-wide"))]
1505    #[inline(never)]
1506    pub fn tan_series_d462<const SCALE: u32>(
1507        raw: crate::int::types::Int<24>,
1508        mode: crate::RoundingMode,
1509    ) -> crate::int::types::Int<24> {
1510        crate::algos::support::wide_trig_core::tan_series::<crate::types::widths::wide_trig_d462::Core, SCALE>(raw, mode)
1511    }
1512    #[cfg(any(feature = "d462", feature = "x-wide"))]
1513    #[inline(never)]
1514    pub fn tan_narrow_d462<const SCALE: u32, const GUARD: u32>(
1515        raw: crate::int::types::Int<24>,
1516        mode: crate::RoundingMode,
1517    ) -> crate::int::types::Int<24> {
1518        crate::algos::trig::sincos_narrow::tan_narrow_with_taylor::<crate::types::widths::wide_trig_d462::Core, SCALE, GUARD, false>(raw, mode)
1519    }
1520    #[cfg(any(feature = "d462", feature = "x-wide"))]
1521    #[inline(never)]
1522    pub fn atan_series_d462<const SCALE: u32>(
1523        raw: crate::int::types::Int<24>,
1524        mode: crate::RoundingMode,
1525    ) -> crate::int::types::Int<24> {
1526        crate::algos::support::wide_trig_core::atan_series::<crate::types::widths::wide_trig_d462::Core, SCALE>(raw, mode)
1527    }
1528    #[cfg(any(feature = "d462", feature = "x-wide"))]
1529    #[inline(never)]
1530    pub fn atan_narrow_d462<const SCALE: u32, const GUARD: u32>(
1531        raw: crate::int::types::Int<24>,
1532        mode: crate::RoundingMode,
1533    ) -> crate::int::types::Int<24> {
1534        crate::algos::support::wide_trig_core::atan_narrow::<crate::types::widths::wide_trig_d462::Core, SCALE, GUARD>(raw, mode)
1535    }
1536
1537    // Forward-trig SCALE-derived work-rung bench seam — tier-width Series
1538    // vs the rung-routed production path (gate + const-folded rung match)
1539    // for the low-scale work-rung A/B (`benches/micro/trig_rung_ab.rs`).
1540    #[cfg(any(feature = "d307", feature = "wide", feature = "x-wide"))]
1541    #[inline(never)]
1542    pub fn sin_series_d307<const SCALE: u32>(
1543        raw: crate::int::types::Int<16>,
1544        mode: crate::RoundingMode,
1545    ) -> crate::int::types::Int<16> {
1546        crate::algos::support::wide_trig_core::sin_series::<crate::types::widths::wide_trig_d307::Core, SCALE>(raw, mode)
1547    }
1548    #[cfg(any(feature = "d307", feature = "wide", feature = "x-wide"))]
1549    #[inline(never)]
1550    pub fn sin_rung_d307<const SCALE: u32>(
1551        raw: crate::int::types::Int<16>,
1552        mode: crate::RoundingMode,
1553    ) -> crate::int::types::Int<16> {
1554        crate::policy::trig::forward_rung::sin_strict::<crate::types::widths::wide_trig_d307::Core, SCALE, { <crate::types::widths::wide_trig_d307::Core as crate::algos::support::wide_trig_core::WideTrigCore>::GUARD }>(raw, mode)
1555    }
1556    #[cfg(any(feature = "d307", feature = "wide", feature = "x-wide"))]
1557    #[inline(never)]
1558    pub fn cos_series_d307<const SCALE: u32>(
1559        raw: crate::int::types::Int<16>,
1560        mode: crate::RoundingMode,
1561    ) -> crate::int::types::Int<16> {
1562        crate::algos::support::wide_trig_core::cos_series::<crate::types::widths::wide_trig_d307::Core, SCALE>(raw, mode)
1563    }
1564    #[cfg(any(feature = "d307", feature = "wide", feature = "x-wide"))]
1565    #[inline(never)]
1566    pub fn cos_rung_d307<const SCALE: u32>(
1567        raw: crate::int::types::Int<16>,
1568        mode: crate::RoundingMode,
1569    ) -> crate::int::types::Int<16> {
1570        crate::policy::trig::forward_rung::cos_strict::<crate::types::widths::wide_trig_d307::Core, SCALE, { <crate::types::widths::wide_trig_d307::Core as crate::algos::support::wide_trig_core::WideTrigCore>::GUARD }>(raw, mode)
1571    }
1572    #[cfg(any(feature = "d307", feature = "wide", feature = "x-wide"))]
1573    #[inline(never)]
1574    pub fn tan_series_d307<const SCALE: u32>(
1575        raw: crate::int::types::Int<16>,
1576        mode: crate::RoundingMode,
1577    ) -> crate::int::types::Int<16> {
1578        crate::algos::support::wide_trig_core::tan_series::<crate::types::widths::wide_trig_d307::Core, SCALE>(raw, mode)
1579    }
1580    #[cfg(any(feature = "d307", feature = "wide", feature = "x-wide"))]
1581    #[inline(never)]
1582    pub fn tan_rung_d307<const SCALE: u32>(
1583        raw: crate::int::types::Int<16>,
1584        mode: crate::RoundingMode,
1585    ) -> crate::int::types::Int<16> {
1586        crate::policy::trig::forward_rung::tan_strict::<crate::types::widths::wide_trig_d307::Core, SCALE, { <crate::types::widths::wide_trig_d307::Core as crate::algos::support::wide_trig_core::WideTrigCore>::GUARD }, true, true>(raw, mode)
1587    }
1588    #[cfg(any(feature = "d1232", feature = "xx-wide"))]
1589    #[inline(never)]
1590    pub fn sin_series_d1232<const SCALE: u32>(
1591        raw: crate::int::types::Int<64>,
1592        mode: crate::RoundingMode,
1593    ) -> crate::int::types::Int<64> {
1594        crate::algos::support::wide_trig_core::sin_series::<crate::types::widths::wide_trig_d1232::Core, SCALE>(raw, mode)
1595    }
1596    #[cfg(any(feature = "d1232", feature = "xx-wide"))]
1597    #[inline(never)]
1598    pub fn sin_rung_d1232<const SCALE: u32>(
1599        raw: crate::int::types::Int<64>,
1600        mode: crate::RoundingMode,
1601    ) -> crate::int::types::Int<64> {
1602        crate::policy::trig::forward_rung::sin_strict::<crate::types::widths::wide_trig_d1232::Core, SCALE, { <crate::types::widths::wide_trig_d1232::Core as crate::algos::support::wide_trig_core::WideTrigCore>::GUARD }>(raw, mode)
1603    }
1604    #[cfg(any(feature = "d1232", feature = "xx-wide"))]
1605    #[inline(never)]
1606    pub fn cos_series_d1232<const SCALE: u32>(
1607        raw: crate::int::types::Int<64>,
1608        mode: crate::RoundingMode,
1609    ) -> crate::int::types::Int<64> {
1610        crate::algos::support::wide_trig_core::cos_series::<crate::types::widths::wide_trig_d1232::Core, SCALE>(raw, mode)
1611    }
1612    #[cfg(any(feature = "d1232", feature = "xx-wide"))]
1613    #[inline(never)]
1614    pub fn cos_rung_d1232<const SCALE: u32>(
1615        raw: crate::int::types::Int<64>,
1616        mode: crate::RoundingMode,
1617    ) -> crate::int::types::Int<64> {
1618        crate::policy::trig::forward_rung::cos_strict::<crate::types::widths::wide_trig_d1232::Core, SCALE, { <crate::types::widths::wide_trig_d1232::Core as crate::algos::support::wide_trig_core::WideTrigCore>::GUARD }>(raw, mode)
1619    }
1620    #[cfg(any(feature = "d1232", feature = "xx-wide"))]
1621    #[inline(never)]
1622    pub fn tan_series_d1232<const SCALE: u32>(
1623        raw: crate::int::types::Int<64>,
1624        mode: crate::RoundingMode,
1625    ) -> crate::int::types::Int<64> {
1626        crate::algos::support::wide_trig_core::tan_series::<crate::types::widths::wide_trig_d1232::Core, SCALE>(raw, mode)
1627    }
1628    #[cfg(any(feature = "d1232", feature = "xx-wide"))]
1629    #[inline(never)]
1630    pub fn tan_rung_d1232<const SCALE: u32>(
1631        raw: crate::int::types::Int<64>,
1632        mode: crate::RoundingMode,
1633    ) -> crate::int::types::Int<64> {
1634        crate::policy::trig::forward_rung::tan_strict::<crate::types::widths::wide_trig_d1232::Core, SCALE, { <crate::types::widths::wide_trig_d1232::Core as crate::algos::support::wide_trig_core::WideTrigCore>::GUARD }, true, true>(raw, mode)
1635    }
1636
1637    // Rung-follow-up bench seam — tier-width kernel vs the rung-routed
1638    // production path for the atan / inverse / hyperbolic / exp families
1639    // (`benches/micro/trig_rung_ab.rs` extensions).
1640    #[cfg(any(feature = "d307", feature = "wide", feature = "x-wide"))]
1641    #[inline(never)]
1642    pub fn atan_series_d307<const SCALE: u32>(
1643        raw: crate::int::types::Int<16>,
1644        mode: crate::RoundingMode,
1645    ) -> crate::int::types::Int<16> {
1646        crate::algos::support::wide_trig_core::atan_series::<crate::types::widths::wide_trig_d307::Core, SCALE>(raw, mode)
1647    }
1648    #[cfg(any(feature = "d307", feature = "wide", feature = "x-wide"))]
1649    #[inline(never)]
1650    pub fn atan_rung_d307<const SCALE: u32>(
1651        raw: crate::int::types::Int<16>,
1652        mode: crate::RoundingMode,
1653    ) -> crate::int::types::Int<16> {
1654        crate::policy::trig::forward_rung::atan_strict::<crate::types::widths::wide_trig_d307::Core, SCALE, { <crate::types::widths::wide_trig_d307::Core as crate::algos::support::wide_trig_core::WideTrigCore>::GUARD }, true>(raw, mode)
1655    }
1656    #[cfg(any(feature = "d307", feature = "wide", feature = "x-wide"))]
1657    #[inline(never)]
1658    pub fn asin_schoolbook_d307<const SCALE: u32>(
1659        raw: crate::int::types::Int<16>,
1660        mode: crate::RoundingMode,
1661    ) -> crate::int::types::Int<16> {
1662        crate::algos::trig::inverse_schoolbook::asin_schoolbook::<crate::types::widths::wide_trig_d307::Core, SCALE>(raw, mode)
1663    }
1664    #[cfg(any(feature = "d307", feature = "wide", feature = "x-wide"))]
1665    #[inline(never)]
1666    pub fn asin_rung_d307<const SCALE: u32>(
1667        raw: crate::int::types::Int<16>,
1668        mode: crate::RoundingMode,
1669    ) -> crate::int::types::Int<16> {
1670        crate::policy::trig::inverse_rung::asin_strict::<crate::types::widths::wide_trig_d307::Core, SCALE>(raw, mode)
1671    }
1672    #[cfg(any(feature = "d307", feature = "wide", feature = "x-wide"))]
1673    #[inline(never)]
1674    pub fn sinh_schoolbook_d307<const SCALE: u32>(
1675        raw: crate::int::types::Int<16>,
1676        mode: crate::RoundingMode,
1677    ) -> crate::int::types::Int<16> {
1678        crate::algos::trig::hyper_schoolbook::sinh_schoolbook::<crate::types::widths::wide_trig_d307::Core, SCALE>(raw, mode)
1679    }
1680    #[cfg(any(feature = "d307", feature = "wide", feature = "x-wide"))]
1681    #[inline(never)]
1682    pub fn sinh_rung_d307<const SCALE: u32>(
1683        raw: crate::int::types::Int<16>,
1684        mode: crate::RoundingMode,
1685    ) -> crate::int::types::Int<16> {
1686        crate::policy::trig::hyper_rung::sinh_strict::<crate::types::widths::wide_trig_d307::Core, SCALE>(raw, mode)
1687    }
1688    #[cfg(any(feature = "d307", feature = "wide", feature = "x-wide"))]
1689    #[inline(never)]
1690    pub fn exp_rung_d307<const SCALE: u32>(
1691        raw: crate::int::types::Int<16>,
1692        mode: crate::RoundingMode,
1693    ) -> crate::int::types::Int<16> {
1694        crate::policy::exp::series_at_rung::<crate::types::widths::wide_trig_d307::Core, SCALE>(raw, mode)
1695    }
1696    #[cfg(any(feature = "d307", feature = "wide", feature = "x-wide"))]
1697    #[inline(never)]
1698    pub fn asinh_schoolbook_d307<const SCALE: u32>(
1699        raw: crate::int::types::Int<16>,
1700        mode: crate::RoundingMode,
1701    ) -> crate::int::types::Int<16> {
1702        crate::algos::trig::hyper_schoolbook::asinh_schoolbook::<crate::types::widths::wide_trig_d307::Core, SCALE>(raw, mode)
1703    }
1704    #[cfg(any(feature = "d307", feature = "wide", feature = "x-wide"))]
1705    #[inline(never)]
1706    pub fn asinh_rung_d307<const SCALE: u32>(
1707        raw: crate::int::types::Int<16>,
1708        mode: crate::RoundingMode,
1709    ) -> crate::int::types::Int<16> {
1710        crate::policy::trig::extra_rung::asinh_strict::<crate::types::widths::wide_trig_d307::Core, SCALE>(raw, mode)
1711    }
1712    #[cfg(any(feature = "d1232", feature = "xx-wide"))]
1713    #[inline(never)]
1714    pub fn atan_series_d1232<const SCALE: u32>(
1715        raw: crate::int::types::Int<64>,
1716        mode: crate::RoundingMode,
1717    ) -> crate::int::types::Int<64> {
1718        crate::algos::support::wide_trig_core::atan_series::<crate::types::widths::wide_trig_d1232::Core, SCALE>(raw, mode)
1719    }
1720    #[cfg(any(feature = "d1232", feature = "xx-wide"))]
1721    #[inline(never)]
1722    pub fn atan_rung_d1232<const SCALE: u32>(
1723        raw: crate::int::types::Int<64>,
1724        mode: crate::RoundingMode,
1725    ) -> crate::int::types::Int<64> {
1726        crate::policy::trig::forward_rung::atan_strict::<crate::types::widths::wide_trig_d1232::Core, SCALE, { <crate::types::widths::wide_trig_d1232::Core as crate::algos::support::wide_trig_core::WideTrigCore>::GUARD }, true>(raw, mode)
1727    }
1728    #[cfg(any(feature = "d1232", feature = "xx-wide"))]
1729    #[inline(never)]
1730    pub fn asin_schoolbook_d1232<const SCALE: u32>(
1731        raw: crate::int::types::Int<64>,
1732        mode: crate::RoundingMode,
1733    ) -> crate::int::types::Int<64> {
1734        crate::algos::trig::inverse_schoolbook::asin_schoolbook::<crate::types::widths::wide_trig_d1232::Core, SCALE>(raw, mode)
1735    }
1736    #[cfg(any(feature = "d1232", feature = "xx-wide"))]
1737    #[inline(never)]
1738    pub fn asin_rung_d1232<const SCALE: u32>(
1739        raw: crate::int::types::Int<64>,
1740        mode: crate::RoundingMode,
1741    ) -> crate::int::types::Int<64> {
1742        crate::policy::trig::inverse_rung::asin_strict::<crate::types::widths::wide_trig_d1232::Core, SCALE>(raw, mode)
1743    }
1744    #[cfg(any(feature = "d1232", feature = "xx-wide"))]
1745    #[inline(never)]
1746    pub fn sinh_rung_d1232<const SCALE: u32>(
1747        raw: crate::int::types::Int<64>,
1748        mode: crate::RoundingMode,
1749    ) -> crate::int::types::Int<64> {
1750        crate::policy::trig::hyper_rung::sinh_strict::<crate::types::widths::wide_trig_d1232::Core, SCALE>(raw, mode)
1751    }
1752    #[cfg(any(feature = "d1232", feature = "xx-wide"))]
1753    #[inline(never)]
1754    pub fn exp_rung_d1232<const SCALE: u32>(
1755        raw: crate::int::types::Int<64>,
1756        mode: crate::RoundingMode,
1757    ) -> crate::int::types::Int<64> {
1758        crate::policy::exp::series_at_rung::<crate::types::widths::wide_trig_d1232::Core, SCALE>(raw, mode)
1759    }
1760    #[cfg(any(feature = "d1232", feature = "xx-wide"))]
1761    #[inline(never)]
1762    pub fn asinh_schoolbook_d1232<const SCALE: u32>(
1763        raw: crate::int::types::Int<64>,
1764        mode: crate::RoundingMode,
1765    ) -> crate::int::types::Int<64> {
1766        crate::algos::trig::hyper_schoolbook::asinh_schoolbook::<crate::types::widths::wide_trig_d1232::Core, SCALE>(raw, mode)
1767    }
1768    #[cfg(any(feature = "d1232", feature = "xx-wide"))]
1769    #[inline(never)]
1770    pub fn asinh_rung_d1232<const SCALE: u32>(
1771        raw: crate::int::types::Int<64>,
1772        mode: crate::RoundingMode,
1773    ) -> crate::int::types::Int<64> {
1774        crate::policy::trig::extra_rung::asinh_strict::<crate::types::widths::wide_trig_d1232::Core, SCALE>(raw, mode)
1775    }
1776
1777    /// `to_radians` candidates for the `to_radians_ab` microbench (the
1778    /// wide-tier angle-conversion path). `direct` calls the
1779    /// `MulPiRatio` kernel straight on the tier `Core` (no policy / resize
1780    /// indirection); `public` goes through the full public method path
1781    /// (`D::to_radians_strict_with` -> `to_radians_dispatch` ->
1782    /// `to_radians::dispatch` -> `mul_pi_ratio_routed`). The gap between the
1783    /// two is the dispatch/resize overhead.
1784    macro_rules! to_radians_bench {
1785        ($direct:ident, $public:ident, $n:literal, $core:ident, $feat:literal) => {
1786            #[cfg(any(feature = $feat, feature = "wide"))]
1787            #[inline(never)]
1788            pub fn $direct<const SCALE: u32>(
1789                raw: crate::int::types::Int<$n>,
1790                mode: crate::RoundingMode,
1791            ) -> crate::int::types::Int<$n> {
1792                crate::algos::trig::angle_mul_pi_ratio::to_radians_mul_pi_ratio::<
1793                    crate::types::widths::$core::Core,
1794                    SCALE,
1795                >(raw, mode)
1796            }
1797            #[cfg(any(feature = $feat, feature = "wide"))]
1798            #[inline(never)]
1799            pub fn $public<const SCALE: u32>(
1800                raw: crate::int::types::Int<$n>,
1801                mode: crate::RoundingMode,
1802            ) -> crate::int::types::Int<$n> {
1803                crate::D::<crate::int::types::Int<$n>, SCALE>(raw)
1804                    .to_radians_strict_with(mode)
1805                    .0
1806            }
1807        };
1808    }
1809    to_radians_bench!(to_radians_direct_d57, to_radians_public_d57, 3, wide_trig_d57, "d57");
1810    to_radians_bench!(to_radians_direct_d76, to_radians_public_d76, 4, wide_trig_d76, "d76");
1811    to_radians_bench!(to_radians_direct_d115, to_radians_public_d115, 6, wide_trig_d115, "d115");
1812    to_radians_bench!(to_radians_direct_d153, to_radians_public_d153, 8, wide_trig_d153, "d153");
1813
1814    /// Build an `Int<N>` from a little-endian magnitude limb array (sign
1815    /// false). Lets the bench construct wide operands without exposing the
1816    /// internal constructors.
1817    #[inline(never)]
1818    pub fn int_from_mag_limbs<const N: usize>(magnitude: &[u64; N]) -> crate::int::types::Int<N> {
1819        crate::int::types::Int::<N>::from_mag_limbs(magnitude, false)
1820    }
1821
1822    #[inline(never)]
1823    pub fn mul_u64_into<const L: usize, const LP1: usize>(
1824        value: &[u64; L],
1825        multiplier: u64,
1826        out: &mut [u64; LP1],
1827    ) {
1828        crate::int::algos::mul::mul_schoolbook::mul_schoolbook_into::<L, LP1>(value, multiplier, out)
1829    }
1830
1831    // ── wide-transcendental `÷10^w` round-divide A/B seam ────────────────
1832    //
1833    // The wide-transcendental kernels reduce a working-scale product by
1834    // exactly `10^w`. Two strategies do this bit-identically (audited in
1835    // `algos::support::mg_divide::tests::round_div_*`):
1836    //   - SLOW: generic Knuth `div_rem` by `10^w` + half-to-even (the
1837    //     macro-local `round_div`);
1838    //   - FAST: the MG / Newton power-of-10 kernel `round_div_pow10`.
1839    // Exposed generic over the work-integer `W` so ONE pair covers every
1840    // wide work width the `div_recover_ab` sweep walks.
1841
1842    /// SLOW path: half-to-even `round(numerator / 10^exponent)` via the
1843    /// generic Knuth
1844    /// `div_rem` reference (mirrors the macro-local `round_div` with a
1845    /// `10^exponent` divisor).
1846    #[inline(never)]
1847    #[allow(private_bounds)]
1848    pub fn round_div_pow10_slow<W: crate::int::types::traits::BigInt>(
1849        numerator: W,
1850        exponent: u32
1851    ) -> W {
1852        let divisor: W = W::TEN.pow(exponent);
1853        let zero = W::ZERO;
1854        let one = W::ONE;
1855        let (quotient, remainder) = numerator.div_rem(divisor);
1856        if remainder == zero {
1857            return quotient;
1858        }
1859        let abs_remainder = if remainder < zero { zero - remainder } else { remainder };
1860        let abs_divisor = if divisor < zero { zero - divisor } else { divisor };
1861        let complement = abs_divisor - abs_remainder;
1862        let remainder_cmp = abs_remainder.cmp(&complement);
1863        // Last decimal digit of |quotient| (a wide `div_rem`, so O(limbs)).
1864        let q_mod_10 = quotient.div_rem(W::TEN).1.to_i128().unsigned_abs() as u8;
1865        let result_positive = (numerator < zero) == (divisor < zero);
1866        if crate::support::rounding::should_bump(
1867            crate::support::rounding::RoundingMode::HalfToEven,
1868            remainder_cmp,
1869            q_mod_10,
1870            result_positive,
1871        ) {
1872            if result_positive { quotient + one } else { quotient - one }
1873        } else {
1874            quotient
1875        }
1876    }
1877
1878    /// FAST path: half-to-even `round(numerator / 10^exponent)` via the
1879    /// production
1880    /// power-of-10 divide kernel (the macro-local `round_div_pow10`):
1881    /// single-chunk MG for `exponent <= 38`, MG / Newton chain dispatch
1882    /// above.
1883    #[inline(never)]
1884    #[allow(private_bounds)]
1885    pub fn round_div_pow10_fast<W>(numerator: W, exponent: u32) -> W
1886    where
1887        W: crate::int::types::traits::BigInt,
1888        W::Scratch: crate::int::types::compute_limbs::ComputeLimbs,
1889    {
1890        if exponent == 0 {
1891            return numerator;
1892        }
1893        if exponent <= 38 {
1894            return crate::algos::support::mg_divide::div_wide_pow10::<W>(
1895                numerator,
1896                exponent,
1897                crate::support::rounding::RoundingMode::HalfToEven,
1898            );
1899        }
1900        crate::algos::support::rescale::dispatch_wide_pow10::<W>(
1901            numerator,
1902            exponent,
1903            crate::support::rounding::RoundingMode::HalfToEven,
1904        )
1905    }
1906
1907    // Newton-reciprocal divide research kernel — wrapped via concrete
1908    // shims so the bench harness gets head-to-head comparisons against
1909    // [`crate::algos::support::mg_divide::div_wide_pow10_chain`] without
1910    // exposing trait machinery.
1911    #[cfg(any(feature = "x-wide", feature = "xx-wide"))]
1912    pub mod newton_vs_mg {
1913        use crate::algos::support::newton_reciprocal::NewtonReciprocal as NR;
1914        pub struct NewtonReciprocal(pub(crate) NR);
1915        impl NewtonReciprocal {
1916            #[inline(never)]
1917            pub fn precompute(scale: u32, width_limbs: usize) -> Self {
1918                Self(NR::precompute(scale, width_limbs))
1919            }
1920        }
1921
1922        macro_rules! shim {
1923            ($pub_name:ident, $width:ty, $feat:literal) => {
1924                #[cfg(any(feature = $feat))]
1925                pub mod $pub_name {
1926                    use super::NewtonReciprocal;
1927                    use crate::RoundingMode;
1928                    type W = $width;
1929
1930                    /// Storage type for this tier — opaque to the bench.
1931                    #[derive(Clone, Copy)]
1932                    pub struct Storage(W);
1933
1934                    /// Build a representative non-zero numerator from a top-limb position.
1935                    /// Buffer sized to 256 u128 limbs to accommodate the widest
1936                    /// tier benched (`Int<512>` = 256 u128 limbs).
1937                    #[inline(never)]
1938                    pub fn build_numerator(top_limb_idx: usize) -> Storage {
1939                        use crate::int::types::traits::BigInt;
1940                        let mut magnitude = [0u128; 256];
1941                        magnitude[top_limb_idx] = 1u128 << 32;
1942                        magnitude[1] = 0xdeadbeef_cafef00d_u128;
1943                        Storage(W::from_mag_sign_u128(&magnitude, false))
1944                    }
1945
1946                    #[inline(never)]
1947                    pub fn mg_chain(numerator: Storage, scale: u32) -> Storage {
1948                        Storage(crate::algos::support::mg_divide::div_wide_pow10_chain::<W>(
1949                            numerator.0,
1950                            scale,
1951                            RoundingMode::HalfToEven,
1952                        ))
1953                    }
1954
1955                    #[inline(never)]
1956                    pub fn mg_single(numerator: Storage, scale: u32) -> Storage {
1957                        Storage(crate::algos::support::mg_divide::div_wide_pow10::<W>(
1958                            numerator.0,
1959                            scale,
1960                            RoundingMode::HalfToEven,
1961                        ))
1962                    }
1963
1964                    #[inline(never)]
1965                    pub fn newton(
1966                        numerator: Storage,
1967                        scale: u32,
1968                        table: &NewtonReciprocal
1969                    ) -> Storage {
1970                        Storage(
1971                            crate::algos::support::newton_reciprocal::div_wide_pow10_newton_with::<W>(
1972                                numerator.0,
1973                                scale,
1974                                RoundingMode::HalfToEven,
1975                                &table.0,
1976                            ),
1977                        )
1978                    }
1979
1980                    /// u128-packed Newton variant. Pre-packs `r` and `pow_scale` at
1981                    /// `precompute` time (cached in the table), then runs the WHOLE
1982                    /// Newton divide entirely on u128 limbs (no per-call pack/unpack
1983                    /// of the cached state, no u128<->u64 transcoding of the operand).
1984                    /// Validity wall: bit-identical to `newton` at every (width,
1985                    /// scale) cell -- verified by the `newton_u64_eq_u128_*` unit
1986                    /// tests in `newton_reciprocal.rs`.
1987                    #[inline(never)]
1988                    pub fn newton_u128(
1989                        numerator: Storage,
1990                        scale: u32,
1991                        table: &NewtonReciprocal
1992                    ) -> Storage {
1993                        use crate::int::types::traits::BigInt;
1994                        // Match production slicing: the Newton kernel operates
1995                        // on EXACTLY `W::U128_LIMBS` u128 limbs (the storage
1996                        // type's width). Passing the whole 256-limb buffer
1997                        // would inflate the schoolbook product cost on smaller
1998                        // widths — production never does that.
1999                        let mut mag_u128 = [0u128; 256];
2000                        let magnitude = &mut mag_u128[..W::U128_LIMBS];
2001                        let is_negative = numerator.0.mag_into_u128(magnitude);
2002                        crate::algos::support::newton_reciprocal::newton_pow10_mag_u128_packed(
2003                            magnitude,
2004                            is_negative,
2005                            RoundingMode::HalfToEven,
2006                            &table.0,
2007                        );
2008                        Storage(W::from_mag_sign_u128(magnitude, is_negative))
2009                    }
2010                }
2011            };
2012        }
2013        shim!(d307, crate::int::types::Int<16>, "x-wide");
2014        // `Int<24>` = 1536-bit storage; matches D462 storage, but ALSO the
2015        // production Work integer used by D230 (Int<12> storage doubles to
2016        // Int<24> for the wide-trig `Work` type). The cells
2017        // `exp_D230_s{172,229}` rescale at this width, so the Newton-vs-MG
2018        // dispatch decision needs `1536`-bit data — hence the dedicated shim
2019        // (the d307/d616/d924/d1232 set skips 1536).
2020        shim!(d462, crate::int::types::Int<24>, "x-wide");
2021        shim!(d616, crate::int::types::Int<32>, "x-wide");
2022        shim!(d924, crate::int::types::Int<48>, "xx-wide");
2023        shim!(d1232, crate::int::types::Int<64>, "xx-wide");
2024        // Int<96>=6144 = D230 Wexp /
2025        // D924 Work. Bench-validated cells extend the Newton-vs-MG
2026        // matrix beyond the 1536-4096 band.
2027        //
2028        // 8192 / 12288 / 16384 / 32768 are NOT exposed here: their
2029        // Newton precompute numerator at the AGM-widened scales
2030        // exceeds the routed Knuth build-max scratch
2031        // (`MAX_SINGLE_LIMBS = 258`), and the integrated-bench picture
2032        // (the atanh diagnosis) suggests MG is the right
2033        // engine at those widths anyway.
2034        shim!(b6144, crate::int::types::Int<96>, "xx-wide");
2035    }
2036
2037    /// `Int<N>` wrapping_neg candidates exposed for the `neg_kernel_ab`
2038    /// dispatch-seam A/B microbench (the wide-tier neg path).
2039    ///
2040    /// Three candidates, all bit-identical:
2041    /// - `neg_fused_split` — the production routed kernel: limb-0
2042    ///   special-cased so the common path (limb 0 != MAX) reduces to
2043    ///   independent `!limb` writes for limbs 1..N with no cross-limb
2044    ///   dependency chain. Wins 1.40x-1.83x at D462/D616/D924/D1232 vs
2045    ///   the previous two-pass form.
2046    /// - `neg_two_pass` — the previous routed shape: NOT loop into
2047    ///   `out[N]`, then a full-width `add_assign_fixed(out, [1, 0, …,
2048    ///   0])` over a second stack array. Retained here for the A/B
2049    ///   seam only.
2050    /// - `neg_fused_open` — single-pass open-coded NOT fused with a
2051    ///   carry-propagating `+1` (dependent carry chain across every
2052    ///   limb). Retained for the A/B; loses to `neg_fused_split` at
2053    ///   wide widths because the dependent chain blocks vectorisation
2054    ///   on the common path.
2055    #[inline(never)]
2056    pub fn neg_fused_split<const N: usize>(
2057        value: crate::int::types::Int<N>,
2058    ) -> crate::int::types::Int<N> {
2059        crate::int::algos::neg::neg_twos_complement::neg_twos_complement::<N>(value)
2060    }
2061    /// Previous routed shape, retained as the `neg_kernel_ab` reference
2062    /// baseline. Bit-identical to `neg_fused_split`.
2063    #[inline(never)]
2064    pub fn neg_two_pass<const N: usize>(
2065        value: crate::int::types::Int<N>
2066    ) -> crate::int::types::Int<N> {
2067        let limbs_in = value.as_limbs();
2068        let mut out = [0u64; N];
2069        let mut i = 0;
2070        while i < N {
2071            out[i] = !limbs_in[i];
2072            i += 1;
2073        }
2074        let mut one = [0u64; N];
2075        if N > 0 {
2076            one[0] = 1;
2077        }
2078        // Inline `add_assign_fixed` so this baseline does not depend on a
2079        // private kernel re-export; bit-identical to the previous
2080        // routed shape.
2081        let mut carry: u64 = 0;
2082        let mut i = 0;
2083        while i < N {
2084            let (s1, c1) = out[i].overflowing_add(one[i]);
2085            let (s2, c2) = s1.overflowing_add(carry);
2086            out[i] = s2;
2087            carry = (c1 as u64) + (c2 as u64);
2088            i += 1;
2089        }
2090        let _ = carry;
2091        crate::int::types::Int::<N>::from_limbs(out)
2092    }
2093    /// Fused open-coded variant: single-pass NOT + carry-propagating
2094    /// `+1`, dependent carry chain across every limb. Retained as a
2095    /// `neg_kernel_ab` candidate; bit-identical to `neg_fused_split`.
2096    #[inline(never)]
2097    pub fn neg_fused_open<const N: usize>(
2098        value: crate::int::types::Int<N>,
2099    ) -> crate::int::types::Int<N> {
2100        let mut out = [0u64; N];
2101        let limbs = value.as_limbs();
2102        let mut carry: u64 = 1;
2103        let mut i = 0;
2104        while i < N {
2105            let (s, c) = (!limbs[i]).overflowing_add(carry);
2106            out[i] = s;
2107            carry = c as u64;
2108            i += 1;
2109        }
2110        let _ = carry;
2111        crate::int::types::Int::<N>::from_limbs(out)
2112    }
2113}
2114mod macros;
2115
2116#[cfg(feature = "cross-scale-ops")]
2117pub mod cross_scale;
2118
2119/// Nightly-gated auto-inferred cross-scale operations. See
2120/// [`mod@cross_scale`] for details.
2121#[cfg(feature = "cross-scale-ops")]
2122pub use crate::cross_scale as cross;
2123
2124// `bitwise` and `num_traits_impls` tests run as Cargo integration
2125// tests under `tests/`. The macro-generated impls themselves are emitted by
2126// `decl_decimal_bitwise!` / `decl_decimal_num_traits_basics!` from
2127// `types/widths.rs`, alongside every other surface.
2128//
2129// The integer layer is unconditional. D38's strict transcendentals use
2130// `Int512` as their guard-digit work integer, so the wide-
2131// integer family must be available in every feature configuration —
2132// not just `feature = "wide"` builds. Compile-time impact is modest:
2133// ~2k LOC of self-contained limb arithmetic plus the const-generic
2134// `Int<N>` / `Uint<N>` monomorphisations.
2135// The integer side of the crate
2136// mirrors the decimal layer's bucket split, all under `int/`:
2137// `int::types` (the `Int<N>`/`Uint<N>` types + named `IntXXXX`
2138// aliases), `int::policy` (algorithm-selection dispatch), and
2139// `int::algos` (width-matched algorithms, including the raw slice limb
2140// primitives in `int::algos::support::limbs`).
2141mod int;
2142mod policy;
2143
2144#[cfg(feature = "serde")]
2145pub use crate::support::serde_helpers;
2146
2147pub use crate::support::error::{ConvertError, ParseError};
2148pub use crate::support::rounding::RoundingMode;
2149pub use crate::types::traits::DecimalConstants;
2150pub use crate::types::traits::Decimal;
2151pub use crate::types::traits::DecimalArithmetic;
2152pub use crate::types::traits::DecimalConvert;
2153pub use crate::types::traits::DecimalTranscendental;
2154pub use crate::types::traits::WidthLE;
2155pub use crate::types::unified::D;
2156
2157#[cfg(feature = "dyn")]
2158pub use crate::types::traits::dyn_decimal::{DecimalWidth, DynDecimal, RawStorage};
2159
2160// D38 — the 128-bit foundation, plus every scale alias D38s0..=D38s37
2161// (scale cap: MAX_SCALE = name - 1).
2162pub use crate::types::widths::{
2163    D38, D38s0, D38s1, D38s2, D38s3, D38s4, D38s5, D38s6, D38s7, D38s8, D38s9, D38s10, D38s11,
2164    D38s12, D38s13, D38s14, D38s15, D38s16, D38s17, D38s18, D38s19, D38s20, D38s21, D38s22, D38s23,
2165    D38s24, D38s25, D38s26, D38s27, D38s28, D38s29, D38s30, D38s31, D38s32, D38s33, D38s34, D38s35,
2166    D38s36, D38s37,
2167};
2168
2169
2170// D18 — 64-bit storage, scale 0..=17 (scale cap: MAX_SCALE = name - 1).
2171pub use crate::types::widths::{
2172    D18, D18s0, D18s1, D18s2, D18s3, D18s4, D18s5, D18s6, D18s7, D18s8, D18s9, D18s10, D18s11,
2173    D18s12, D18s13, D18s14, D18s15, D18s16, D18s17,
2174};
2175
2176// The generic hand-rolled integer `Int<N>` (and unsigned `Uint<N>`) — the
2177// storage backend for D38 (`Int<2>`) and every wide tier. Exported so callers
2178// can name a decimal's storage type, e.g. for `from_bits` / `to_bits`. The
2179// fixed-width aliases (`Int256`, …) are the same types at specific `N`.
2180pub use crate::int::types::{Int, Uint};
2181
2182// Wide-tier scale aliases (D76 and up) are a CURATED convenience subset,
2183// unlike the exhaustive D18/D38 lists above. Every scale in a tier's range
2184// is still valid — write `D76<S>` (etc.) directly for scales without an
2185// alias.
2186
2187// D76 — 256-bit storage, behind the `d76` / `wide` features.
2188#[cfg(any(feature = "d76", feature = "wide"))]
2189pub use crate::types::widths::{
2190    D76, D76s0, D76s1, D76s2, D76s3, D76s4, D76s6, D76s9, D76s12, D76s15, D76s18, D76s20, D76s24,
2191    D76s28, D76s32, D76s35, D76s38, D76s42, D76s48, D76s50, D76s56, D76s64, D76s70, D76s75,
2192};
2193
2194
2195// D153 — 512-bit storage, behind the `d153` / `wide` features.
2196#[cfg(any(feature = "d153", feature = "wide"))]
2197pub use crate::types::widths::{
2198    D153, D153s0, D153s1, D153s2, D153s4, D153s6, D153s9, D153s12, D153s15, D153s18, D153s20,
2199    D153s24, D153s28, D153s32, D153s35, D153s38, D153s50, D153s57, D153s75, D153s76, D153s100,
2200    D153s115, D153s140, D153s150, D153s152,
2201};
2202
2203// D307 — 1024-bit storage, behind the `d307` / `wide` features.
2204#[cfg(any(feature = "d307", feature = "wide"))]
2205pub use crate::types::widths::{
2206    D307, D307s0, D307s1, D307s2, D307s4, D307s6, D307s9, D307s12, D307s15, D307s18, D307s20,
2207    D307s24, D307s28, D307s32, D307s35, D307s38, D307s50, D307s75, D307s100, D307s115, D307s150,
2208    D307s153, D307s200, D307s230, D307s275, D307s300, D307s306,
2209};
2210
2211// ─── New half-width and wider tiers ───────────────────────────────────
2212
2213// D57 — 192-bit storage; half-width between D38 and D76.
2214#[cfg(any(feature = "d57", feature = "wide"))]
2215pub use crate::types::widths::{
2216    D57, D57s0, D57s1, D57s2, D57s4, D57s6, D57s9, D57s12, D57s18, D57s20, D57s24, D57s28, D57s32,
2217    D57s38, D57s42, D57s48, D57s52, D57s56,
2218};
2219
2220// D115 — 384-bit; half-width between D76 and D153.
2221#[cfg(any(feature = "d115", feature = "wide"))]
2222pub use crate::types::widths::{
2223    D115, D115s0, D115s1, D115s4, D115s8, D115s16, D115s24, D115s32, D115s38, D115s50, D115s57,
2224    D115s64, D115s76, D115s90, D115s100, D115s110, D115s114,
2225};
2226
2227// D230 — 768-bit; half-width between D153 and D307.
2228#[cfg(any(feature = "d230", feature = "wide"))]
2229pub use crate::types::widths::{
2230    D230, D230s0, D230s1, D230s6, D230s18, D230s38, D230s57, D230s75, D230s100, D230s115, D230s140,
2231    D230s153, D230s175, D230s200, D230s215, D230s225, D230s229,
2232};
2233
2234// D462 — 1536-bit; half-width between D307 and D616.
2235#[cfg(any(feature = "d462", feature = "x-wide"))]
2236pub use crate::types::widths::{
2237    D462, D462s0, D462s1, D462s18, D462s38, D462s75, D462s115, D462s153, D462s200, D462s230,
2238    D462s275, D462s307, D462s350, D462s400, D462s440, D462s460, D462s461,
2239};
2240
2241// D616 — 2048-bit; new top wide tier. Int2048 / Uint2048 are
2242// already exported above for x-wide / d307 widening; no re-export
2243// here.
2244#[cfg(any(feature = "d616", feature = "x-wide"))]
2245pub use crate::types::widths::{
2246    D616, D616s0, D616s1, D616s38, D616s75, D616s115, D616s153, D616s200, D616s230, D616s275,
2247    D616s308, D616s380, D616s462, D616s500, D616s555, D616s600, D616s615,
2248};
2249
2250// D924 — 3072-bit; half-width between D616 and D1232.
2251#[cfg(any(feature = "d924", feature = "xx-wide"))]
2252pub use crate::types::widths::{
2253    D924, D924s0, D924s1, D924s75, D924s153, D924s230, D924s307, D924s400, D924s461, D924s462,
2254    D924s500, D924s616, D924s700, D924s800, D924s860, D924s900, D924s920, D924s923,
2255};
2256
2257// D1232 — 4096-bit; widest tier shipped.
2258#[cfg(any(feature = "d1232", feature = "xx-wide"))]
2259pub use crate::types::widths::{
2260    D1232, D1232s0, D1232s1, D1232s75, D1232s153, D1232s230, D1232s307, D1232s461, D1232s616,
2261    D1232s700, D1232s800, D1232s900, D1232s924, D1232s1000, D1232s1100, D1232s1180, D1232s1220,
2262    D1232s1230, D1232s1231,
2263};
2264
2265// ─── Construction macros (re-exports + per-scale wrappers) ────────────
2266
2267/// The narrow-tier proc-macros are always available with the
2268/// `macros` feature; the wide-tier proc-macros are additionally
2269/// feature-gated to match their target type's availability.
2270#[cfg(feature = "macros")]
2271pub use decimal_scaled_macros::{d18, d38};
2272
2273#[cfg(all(feature = "macros", any(feature = "d76", feature = "wide")))]
2274pub use decimal_scaled_macros::d76;
2275
2276#[cfg(all(feature = "macros", any(feature = "d153", feature = "wide")))]
2277pub use decimal_scaled_macros::d153;
2278
2279#[cfg(all(
2280    feature = "macros",
2281    any(feature = "d307", feature = "wide", feature = "x-wide")
2282))]
2283pub use decimal_scaled_macros::d307;
2284
2285#[cfg(all(feature = "macros", any(feature = "d57", feature = "wide")))]
2286pub use decimal_scaled_macros::d57;
2287
2288#[cfg(all(feature = "macros", any(feature = "d115", feature = "wide")))]
2289pub use decimal_scaled_macros::d115;
2290
2291#[cfg(all(feature = "macros", any(feature = "d230", feature = "wide")))]
2292pub use decimal_scaled_macros::d230;
2293
2294#[cfg(all(feature = "macros", any(feature = "d462", feature = "x-wide")))]
2295pub use decimal_scaled_macros::d462;
2296
2297#[cfg(all(feature = "macros", any(feature = "d616", feature = "x-wide")))]
2298pub use decimal_scaled_macros::d616;
2299
2300#[cfg(all(feature = "macros", any(feature = "d924", feature = "xx-wide")))]
2301pub use decimal_scaled_macros::d924;
2302
2303#[cfg(all(feature = "macros", any(feature = "d1232", feature = "xx-wide")))]
2304pub use decimal_scaled_macros::d1232;
2305
2306// Per-scale wrappers — curated subset of pre-baked
2307// `<dN>s<SCALE>!` macros that forward to the corresponding
2308// proc-macro with `scale N` added. Long-tail scales remain
2309// reachable via the explicit `, scale N` qualifier.
2310//
2311// Each alias is a tiny `macro_rules!`. We don't generate them
2312// through a nested macro because `macro_rules!` doesn't support
2313// directly emitting another `macro_rules!` without `$$` escapes
2314// that aren't available in stable Rust; explicit per-line
2315// declarations keep things debuggable and only cost ~40 lines.
2316
2317/// `d18s0!(value)` — equivalent to `d18!(value, scale 0)`.
2318#[cfg(feature = "macros")]
2319#[macro_export]
2320macro_rules! d18s0  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d18!($v, scale 0  $(, $($rest)*)?) }; }
2321/// `d18s2!(value)` — equivalent to `d18!(value, scale 2)`.
2322#[cfg(feature = "macros")]
2323#[macro_export]
2324macro_rules! d18s2  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d18!($v, scale 2  $(, $($rest)*)?) }; }
2325/// `d18s4!(value)` — equivalent to `d18!(value, scale 4)`.
2326#[cfg(feature = "macros")]
2327#[macro_export]
2328macro_rules! d18s4  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d18!($v, scale 4  $(, $($rest)*)?) }; }
2329/// `d18s6!(value)` — equivalent to `d18!(value, scale 6)`.
2330#[cfg(feature = "macros")]
2331#[macro_export]
2332macro_rules! d18s6  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d18!($v, scale 6  $(, $($rest)*)?) }; }
2333/// `d18s9!(value)` — equivalent to `d18!(value, scale 9)`.
2334#[cfg(feature = "macros")]
2335#[macro_export]
2336macro_rules! d18s9  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d18!($v, scale 9  $(, $($rest)*)?) }; }
2337/// `d18s12!(value)` — equivalent to `d18!(value, scale 12)`.
2338#[cfg(feature = "macros")]
2339#[macro_export]
2340macro_rules! d18s12 { ($v:tt $(, $($rest:tt)*)?) => { $crate::d18!($v, scale 12 $(, $($rest)*)?) }; }
2341
2342// D38 curated scales.
2343/// `d38s0!(value)` — equivalent to `d38!(value, scale 0)`.
2344#[cfg(feature = "macros")]
2345#[macro_export]
2346macro_rules! d38s0  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d38!($v, scale 0  $(, $($rest)*)?) }; }
2347/// `d38s2!(value)` — equivalent to `d38!(value, scale 2)`.
2348#[cfg(feature = "macros")]
2349#[macro_export]
2350macro_rules! d38s2  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d38!($v, scale 2  $(, $($rest)*)?) }; }
2351/// `d38s4!(value)` — equivalent to `d38!(value, scale 4)`.
2352#[cfg(feature = "macros")]
2353#[macro_export]
2354macro_rules! d38s4  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d38!($v, scale 4  $(, $($rest)*)?) }; }
2355/// `d38s6!(value)` — equivalent to `d38!(value, scale 6)`.
2356#[cfg(feature = "macros")]
2357#[macro_export]
2358macro_rules! d38s6  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d38!($v, scale 6  $(, $($rest)*)?) }; }
2359/// `d38s8!(value)` — equivalent to `d38!(value, scale 8)`.
2360#[cfg(feature = "macros")]
2361#[macro_export]
2362macro_rules! d38s8  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d38!($v, scale 8  $(, $($rest)*)?) }; }
2363/// `d38s9!(value)` — equivalent to `d38!(value, scale 9)`.
2364#[cfg(feature = "macros")]
2365#[macro_export]
2366macro_rules! d38s9  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d38!($v, scale 9  $(, $($rest)*)?) }; }
2367/// `d38s12!(value)` — equivalent to `d38!(value, scale 12)`.
2368#[cfg(feature = "macros")]
2369#[macro_export]
2370macro_rules! d38s12 { ($v:tt $(, $($rest:tt)*)?) => { $crate::d38!($v, scale 12 $(, $($rest)*)?) }; }
2371/// `d38s15!(value)` — equivalent to `d38!(value, scale 15)`.
2372#[cfg(feature = "macros")]
2373#[macro_export]
2374macro_rules! d38s15 { ($v:tt $(, $($rest:tt)*)?) => { $crate::d38!($v, scale 15 $(, $($rest)*)?) }; }
2375/// `d38s18!(value)` — equivalent to `d38!(value, scale 18)`.
2376#[cfg(feature = "macros")]
2377#[macro_export]
2378macro_rules! d38s18 { ($v:tt $(, $($rest:tt)*)?) => { $crate::d38!($v, scale 18 $(, $($rest)*)?) }; }
2379/// `d38s24!(value)` — equivalent to `d38!(value, scale 24)`.
2380#[cfg(feature = "macros")]
2381#[macro_export]
2382macro_rules! d38s24 { ($v:tt $(, $($rest:tt)*)?) => { $crate::d38!($v, scale 24 $(, $($rest)*)?) }; }
2383/// `d38s35!(value)` — equivalent to `d38!(value, scale 35)`.
2384#[cfg(feature = "macros")]
2385#[macro_export]
2386macro_rules! d38s35 { ($v:tt $(, $($rest:tt)*)?) => { $crate::d38!($v, scale 35 $(, $($rest)*)?) }; }
2387
2388// D76 curated scales.
2389/// `d76s0!(value)` — equivalent to `d76!(value, scale 0)`.
2390#[cfg(all(feature = "macros", any(feature = "d76", feature = "wide")))]
2391#[macro_export]
2392macro_rules! d76s0  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d76!($v, scale 0  $(, $($rest)*)?) }; }
2393/// `d76s2!(value)` — equivalent to `d76!(value, scale 2)`.
2394#[cfg(all(feature = "macros", any(feature = "d76", feature = "wide")))]
2395#[macro_export]
2396macro_rules! d76s2  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d76!($v, scale 2  $(, $($rest)*)?) }; }
2397/// `d76s6!(value)` — equivalent to `d76!(value, scale 6)`.
2398#[cfg(all(feature = "macros", any(feature = "d76", feature = "wide")))]
2399#[macro_export]
2400macro_rules! d76s6  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d76!($v, scale 6  $(, $($rest)*)?) }; }
2401/// `d76s12!(value)` — equivalent to `d76!(value, scale 12)`.
2402#[cfg(all(feature = "macros", any(feature = "d76", feature = "wide")))]
2403#[macro_export]
2404macro_rules! d76s12 { ($v:tt $(, $($rest:tt)*)?) => { $crate::d76!($v, scale 12 $(, $($rest)*)?) }; }
2405/// `d76s18!(value)` — equivalent to `d76!(value, scale 18)`.
2406#[cfg(all(feature = "macros", any(feature = "d76", feature = "wide")))]
2407#[macro_export]
2408macro_rules! d76s18 { ($v:tt $(, $($rest:tt)*)?) => { $crate::d76!($v, scale 18 $(, $($rest)*)?) }; }
2409/// `d76s35!(value)` — equivalent to `d76!(value, scale 35)`.
2410#[cfg(all(feature = "macros", any(feature = "d76", feature = "wide")))]
2411#[macro_export]
2412macro_rules! d76s35 { ($v:tt $(, $($rest:tt)*)?) => { $crate::d76!($v, scale 35 $(, $($rest)*)?) }; }
2413/// `d76s50!(value)` — equivalent to `d76!(value, scale 50)`.
2414#[cfg(all(feature = "macros", any(feature = "d76", feature = "wide")))]
2415#[macro_export]
2416macro_rules! d76s50 { ($v:tt $(, $($rest:tt)*)?) => { $crate::d76!($v, scale 50 $(, $($rest)*)?) }; }
2417
2418// D153 curated scales.
2419/// `d153s0!(value)` — equivalent to `d153!(value, scale 0)`.
2420#[cfg(all(feature = "macros", any(feature = "d153", feature = "wide")))]
2421#[macro_export]
2422macro_rules! d153s0   { ($v:tt $(, $($rest:tt)*)?) => { $crate::d153!($v, scale 0   $(, $($rest)*)?) }; }
2423/// `d153s35!(value)` — equivalent to `d153!(value, scale 35)`.
2424#[cfg(all(feature = "macros", any(feature = "d153", feature = "wide")))]
2425#[macro_export]
2426macro_rules! d153s35  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d153!($v, scale 35  $(, $($rest)*)?) }; }
2427/// `d153s75!(value)` — equivalent to `d153!(value, scale 75)`.
2428#[cfg(all(feature = "macros", any(feature = "d153", feature = "wide")))]
2429#[macro_export]
2430macro_rules! d153s75  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d153!($v, scale 75  $(, $($rest)*)?) }; }
2431/// `d153s150!(value)` — equivalent to `d153!(value, scale 150)`.
2432#[cfg(all(feature = "macros", any(feature = "d153", feature = "wide")))]
2433#[macro_export]
2434macro_rules! d153s150 { ($v:tt $(, $($rest:tt)*)?) => { $crate::d153!($v, scale 150 $(, $($rest)*)?) }; }
2435
2436// D307 curated scales.
2437/// `d307s0!(value)` — equivalent to `d307!(value, scale 0)`.
2438#[cfg(all(
2439    feature = "macros",
2440    any(feature = "d307", feature = "wide", feature = "x-wide")
2441))]
2442#[macro_export]
2443macro_rules! d307s0   { ($v:tt $(, $($rest:tt)*)?) => { $crate::d307!($v, scale 0   $(, $($rest)*)?) }; }
2444/// `d307s35!(value)` — equivalent to `d307!(value, scale 35)`.
2445#[cfg(all(
2446    feature = "macros",
2447    any(feature = "d307", feature = "wide", feature = "x-wide")
2448))]
2449#[macro_export]
2450macro_rules! d307s35  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d307!($v, scale 35  $(, $($rest)*)?) }; }
2451/// `d307s150!(value)` — equivalent to `d307!(value, scale 150)`.
2452#[cfg(all(
2453    feature = "macros",
2454    any(feature = "d307", feature = "wide", feature = "x-wide")
2455))]
2456#[macro_export]
2457macro_rules! d307s150 { ($v:tt $(, $($rest:tt)*)?) => { $crate::d307!($v, scale 150 $(, $($rest)*)?) }; }
2458/// `d307s300!(value)` — equivalent to `d307!(value, scale 300)`.
2459#[cfg(all(
2460    feature = "macros",
2461    any(feature = "d307", feature = "wide", feature = "x-wide")
2462))]
2463#[macro_export]
2464macro_rules! d307s300 { ($v:tt $(, $($rest:tt)*)?) => { $crate::d307!($v, scale 300 $(, $($rest)*)?) }; }