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 `rescale::<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(a: &[u64], b: &[u64], out: &mut [u64]) {
221        crate::int::algos::mul::mul_schoolbook::mul_schoolbook(a, b, 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>(a: &[u64; N], b: &[u64; N], out: &mut [u64; N]) {
229        crate::int::algos::mul::mul_schoolbook::mul_low_limb::<N, u64>(a, b, 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>(a: &[u64; N], b: &[u64; N], out: &mut [u64; N]) {
238        crate::int::algos::mul::mul_schoolbook::mul_low_limb::<N, u128>(a, b, 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(a: &[u64; $n], b: &[u64; $n], out: &mut [u64]) {
255                crate::int::algos::mul::mul_schoolbook::mul_full_limb::<$n, u64>(a, b, out)
256            }
257        };
258        // both u64 + u128 (even N)
259        ($u64name:ident, $u128name:ident, $n:literal) => {
260            #[inline(never)]
261            pub fn $u64name(a: &[u64; $n], b: &[u64; $n], out: &mut [u64]) {
262                crate::int::algos::mul::mul_schoolbook::mul_full_limb::<$n, u64>(a, b, out)
263            }
264            #[inline(never)]
265            pub fn $u128name(a: &[u64; $n], b: &[u64; $n], out: &mut [u64]) {
266                crate::int::algos::mul::mul_schoolbook::mul_full_limb::<$n, u128>(a, b, 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>(x: &[u64; N], out: &mut [u64; N]) {
291        crate::int::algos::sqr::sqr_low_limb::sqr_low_limb::<N, u64>(x, 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>(x: &[u64; N], out: &mut [u64; N]) {
300        crate::int::algos::sqr::sqr_low_limb::sqr_low_limb::<N, u128>(x, out)
301    }
302    #[inline(never)]
303    pub fn mul_fixed<const L: usize, const D: usize>(
304        a: &[u64; L],
305        b: &[u64; L],
306        out: &mut [u64; D],
307    ) {
308        crate::int::algos::mul::mul_schoolbook::mul_schoolbook_fixed::<L, D>(a, b, 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(a: &[u64], b: &[u64], out: &mut [u64], threshold: usize) {
317        crate::int::algos::mul::mul_karatsuba::mul_karatsuba_forced(a, b, 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(a: &[u64; $n], b: &[u64; $n], out: &mut [u64]) {
328                crate::int::algos::mul::mul_karatsuba::mul_karatsuba_limb::<$n, u64>(a, b, out, $n)
329            }
330        };
331        ($u64name:ident, $u128name:ident, $n:literal) => {
332            #[inline(never)]
333            pub fn $u64name(a: &[u64; $n], b: &[u64; $n], out: &mut [u64]) {
334                crate::int::algos::mul::mul_karatsuba::mul_karatsuba_limb::<$n, u64>(a, b, out, $n)
335            }
336            #[inline(never)]
337            pub fn $u128name(a: &[u64; $n], b: &[u64; $n], out: &mut [u64]) {
338                crate::int::algos::mul::mul_karatsuba::mul_karatsuba_limb::<$n, u128>(a, b, 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(a: &[u64; $n], b: &[u64; $n], out: &mut [u64], threshold: usize) {
362                crate::int::algos::mul::mul_karatsuba::mul_karatsuba_limb::<$n, u128>(a, b, 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(a: &[u64], b: &[u64], out: &mut [u64]) {
374        crate::int::algos::mul::mul_toom3::mul_toom3(a, b, 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(a: &[u64; $n], b: &[u64; $n], out: &mut [u64]) {
385                crate::int::algos::mul::mul_toom3::mul_toom3_limb::<$n, u64>(a, b, out)
386            }
387            #[inline(never)]
388            pub fn $u128name(a: &[u64; $n], b: &[u64; $n], out: &mut [u64]) {
389                crate::int::algos::mul::mul_toom3::mul_toom3_limb::<$n, u128>(a, b, 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(num: &[u64], den: &[u64], quot: &mut [u64], rem: &mut [u64]) {
407        crate::int::algos::div::div_knuth::div_knuth(num, den, quot, rem)
408    }
409    #[inline(never)]
410    pub fn div_dispatch_slice(num: &[u64], den: &[u64], quot: &mut [u64], rem: &mut [u64]) {
411        crate::int::policy::div_rem::dispatch(num, den, quot, rem)
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(num: &[u64], den: &[u64], quot: &mut [u64], rem: &mut [u64]) {
420        crate::int::algos::div::div_knuth_u128_limb::div_knuth_u128_limb(num, den, quot, rem)
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(num: &[u64], den: &[u64], quot: &mut [u64], rem: &mut [u64]) {
427        crate::int::algos::div::div_burnikel_ziegler_with_knuth::bz_chunk_core_forced(
428            num, den, quot, rem,
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(num: &[u64], den: &[u64], quot: &mut [u64], rem: &mut [u64]) {
437        crate::int::algos::div::div_rem::div_rem(num, den, quot, rem)
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(num: &[u64], den: &[u64], quot: &mut [u64], rem: &mut [u64]) {
445        crate::int::algos::div::div_rem_schoolbook::div_rem_schoolbook(num, den, quot, rem)
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        a: crate::int::types::Int<N>,
455        b: 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>(a, b, mode)
462    }
463    #[inline(never)]
464    #[allow(private_bounds)]
465    pub fn hypot_u128_fast<const N: usize>(
466        a: crate::int::types::Int<N>,
467        b: 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>(a, b, 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        a: crate::int::types::Int<N>,
482        b: crate::int::types::Int<N>,
483    ) -> crate::int::types::Int<N> {
484        crate::int::algos::rem::rem_native::rem_native::<N>(a, b)
485    }
486    #[inline(never)]
487    pub fn rem_via_div_rem<const N: usize>(
488        a: crate::int::types::Int<N>,
489        b: 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>(a, b)
492    }
493    #[inline(never)]
494    pub fn rem_schoolbook<const N: usize>(
495        a: crate::int::types::Int<N>,
496        b: crate::int::types::Int<N>,
497    ) -> crate::int::types::Int<N> {
498        crate::int::algos::rem::rem_schoolbook::rem_schoolbook::<N>(a, b)
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        a: crate::int::types::Int<N>,
506        b: crate::int::types::Int<N>,
507    ) -> crate::int::types::Int<N> {
508        crate::int::algos::rem::rem_small_fast::rem_small_fast::<N>(a, b)
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        a: crate::int::types::Int<N>,
515        b: crate::int::types::Int<N>,
516    ) -> crate::int::types::Int<N> {
517        crate::int::algos::rem::rem_native_direct::rem_native_direct::<N>(a, b)
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        x: crate::int::types::Uint<N>,
526    ) -> crate::int::types::Uint<N> {
527        crate::int::algos::sqr::sqr_half_product::sqr_half_product::<N>(x)
528    }
529    #[inline(never)]
530    pub fn sqr_schoolbook<const N: usize>(
531        x: crate::int::types::Uint<N>,
532    ) -> crate::int::types::Uint<N> {
533        crate::int::algos::sqr::sqr_schoolbook::sqr_schoolbook::<N>(x)
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(n: &[u64], out: &mut [u64]) {
559        crate::int::algos::isqrt::isqrt_newton::isqrt_newton(n, out)
560    }
561    #[inline(never)]
562    pub fn isqrt_schoolbook_slice(n: &[u64], out: &mut [u64]) {
563        crate::int::algos::isqrt::isqrt_schoolbook::isqrt_schoolbook(n, 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>(n: &[u64; N], out: &mut [u64; N]) {
575        crate::int::algos::isqrt::isqrt_mag_fixed::isqrt_mag_fixed::<N>(n, 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(n: &[u64], out: &mut [u64]) {
583        crate::int::algos::icbrt::icbrt_newton::icbrt_newton(n, out)
584    }
585    #[inline(never)]
586    pub fn icbrt_schoolbook_slice(n: &[u64], out: &mut [u64]) {
587        crate::int::algos::icbrt::icbrt_schoolbook::icbrt_schoolbook(n, 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(n: &[u64], out: &mut [u64]) {
597        crate::int::algos::isqrt::isqrt_karatsuba::isqrt_karatsuba(n, 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(n: &[u64], out: &mut [u64]) {
607        crate::int::algos::icbrt::icbrt_newton_recip::icbrt_newton_recip(n, 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        x: crate::int::types::Uint<N>,
617    ) -> crate::int::types::Uint<N> {
618        crate::int::algos::cube::cube_schoolbook::cube_schoolbook::<N>(x)
619    }
620    #[inline(never)]
621    pub fn cube_fused_comba<const N: usize>(
622        x: crate::int::types::Uint<N>,
623    ) -> crate::int::types::Uint<N> {
624        crate::int::algos::cube::cube_fused_comba::cube_fused_comba::<N>(x)
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        a: crate::int::types::Int<N>,
634        b: crate::int::types::Int<N>,
635    ) -> bool {
636        crate::int::algos::eq::eq_limbwise::eq_limbwise::<N>(a, b)
637    }
638    #[inline(never)]
639    pub fn eq_xor_fold<const N: usize>(
640        a: crate::int::types::Int<N>,
641        b: crate::int::types::Int<N>,
642    ) -> bool {
643        crate::int::algos::eq::eq_xor_fold::eq_xor_fold::<N>(a, b)
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                a: crate::int::types::Int<$n>,
659                b: 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>(a, b)
662            }
663            #[inline(never)]
664            pub fn $cb(
665                a: crate::int::types::Int<$n>,
666                b: 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>(a, b)
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        a: crate::int::types::Int<N>,
691        b: 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>(a, b, mode)
695    }
696    #[inline(never)]
697    pub fn dec_div_widen_scale_n1(
698        a: crate::int::types::Int<1>,
699        b: crate::int::types::Int<1>,
700        mult: 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>(a, b, mult, mode)
704    }
705    #[inline(never)]
706    pub fn dec_div_widen_scale_n2(
707        a: crate::int::types::Int<2>,
708        b: crate::int::types::Int<2>,
709        mult: 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>(a, b, mult, 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        a: crate::int::types::Int<N>,
719        b: 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>(a, b, mode)
723    }
724    #[inline(never)]
725    pub fn dec_mul_widen_divide_n1<const SCALE: u32>(
726        a: crate::int::types::Int<1>,
727        b: 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>(a, b, mode)
731    }
732    #[inline(never)]
733    pub fn dec_mul_widen_divide_n2<const SCALE: u32>(
734        a: crate::int::types::Int<2>,
735        b: 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>(a, b, 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        a: crate::int::types::Int<N>,
748        b: 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>(a, b, 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        a: crate::int::types::Int<N>,
762        b: 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>(a, b)
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        a: crate::int::types::Int<N>,
777        b: 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>(a, b)
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        a: crate::int::types::Int<N>,
792        b: crate::int::types::Int<N>,
793    ) -> crate::int::types::Int<N> {
794        a.wrapping_rem(b)
795    }
796    #[inline(never)]
797    pub fn dec_rem_native<const N: usize>(
798        a: crate::int::types::Int<N>,
799        b: crate::int::types::Int<N>,
800    ) -> crate::int::types::Int<N> {
801        crate::algos::rem::rem_native::rem_native::<N>(a, b)
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>(mag: &[u64; N]) -> crate::int::types::Int<N> {
1819        crate::int::types::Int::<N>::from_mag_limbs(mag, false)
1820    }
1821
1822    #[inline(never)]
1823    pub fn mul_u64_into<const L: usize, const LP1: usize>(
1824        a: &[u64; L],
1825        n: u64,
1826        out: &mut [u64; LP1],
1827    ) {
1828        crate::int::algos::mul::mul_schoolbook::mul_schoolbook_into::<L, LP1>(a, n, 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(n / 10^w)` via the generic Knuth
1843    /// `div_rem` reference (mirrors the macro-local `round_div` with a
1844    /// `10^w` divisor).
1845    #[inline(never)]
1846    #[allow(private_bounds)]
1847    pub fn round_div_pow10_slow<W: crate::int::types::traits::BigInt>(n: W, w: u32) -> W {
1848        let d: W = W::TEN.pow(w);
1849        let zero = W::ZERO;
1850        let one = W::ONE;
1851        let (q, r) = n.div_rem(d);
1852        if r == zero {
1853            return q;
1854        }
1855        let ar = if r < zero { zero - r } else { r };
1856        let ad = if d < zero { zero - d } else { d };
1857        let comp = ad - ar;
1858        let cmp_r = ar.cmp(&comp);
1859        let q_is_odd = q.bit(0);
1860        let result_positive = (n < zero) == (d < zero);
1861        if crate::support::rounding::should_bump(
1862            crate::support::rounding::RoundingMode::HalfToEven,
1863            cmp_r,
1864            q_is_odd,
1865            result_positive,
1866        ) {
1867            if result_positive { q + one } else { q - one }
1868        } else {
1869            q
1870        }
1871    }
1872
1873    /// FAST path: half-to-even `round(n / 10^w)` via the production
1874    /// power-of-10 divide kernel (the macro-local `round_div_pow10`):
1875    /// single-chunk MG for `w <= 38`, MG / Newton chain dispatch above.
1876    #[inline(never)]
1877    #[allow(private_bounds)]
1878    pub fn round_div_pow10_fast<W>(n: W, w: u32) -> W
1879    where
1880        W: crate::int::types::traits::BigInt,
1881        W::Scratch: crate::int::types::compute_limbs::ComputeLimbs,
1882    {
1883        if w == 0 {
1884            return n;
1885        }
1886        if w <= 38 {
1887            return crate::algos::support::mg_divide::div_wide_pow10::<W>(
1888                n,
1889                w,
1890                crate::support::rounding::RoundingMode::HalfToEven,
1891            );
1892        }
1893        crate::algos::support::rescale::dispatch_wide_pow10::<W>(
1894            n,
1895            w,
1896            crate::support::rounding::RoundingMode::HalfToEven,
1897        )
1898    }
1899
1900    // Newton-reciprocal divide research kernel — wrapped via concrete
1901    // shims so the bench harness gets head-to-head comparisons against
1902    // [`crate::algos::support::mg_divide::div_wide_pow10_chain`] without
1903    // exposing trait machinery.
1904    #[cfg(any(feature = "x-wide", feature = "xx-wide"))]
1905    pub mod newton_vs_mg {
1906        use crate::algos::support::newton_reciprocal::NewtonReciprocal as NR;
1907        pub struct NewtonReciprocal(pub(crate) NR);
1908        impl NewtonReciprocal {
1909            #[inline(never)]
1910            pub fn precompute(scale: u32, width_limbs: usize) -> Self {
1911                Self(NR::precompute(scale, width_limbs))
1912            }
1913        }
1914
1915        macro_rules! shim {
1916            ($pub_name:ident, $width:ty, $feat:literal) => {
1917                #[cfg(any(feature = $feat))]
1918                pub mod $pub_name {
1919                    use super::NewtonReciprocal;
1920                    use crate::RoundingMode;
1921                    type W = $width;
1922
1923                    /// Storage type for this tier — opaque to the bench.
1924                    #[derive(Clone, Copy)]
1925                    pub struct Storage(W);
1926
1927                    /// Build a representative non-zero numerator from a top-limb position.
1928                    /// Buffer sized to 256 u128 limbs to accommodate the widest
1929                    /// tier benched (`Int<512>` = 256 u128 limbs).
1930                    #[inline(never)]
1931                    pub fn build_numerator(top_limb_idx: usize) -> Storage {
1932                        use crate::int::types::traits::BigInt;
1933                        let mut mag = [0u128; 256];
1934                        mag[top_limb_idx] = 1u128 << 32;
1935                        mag[1] = 0xdeadbeef_cafef00d_u128;
1936                        Storage(W::from_mag_sign_u128(&mag, false))
1937                    }
1938
1939                    #[inline(never)]
1940                    pub fn mg_chain(n: Storage, scale: u32) -> Storage {
1941                        Storage(crate::algos::support::mg_divide::div_wide_pow10_chain::<W>(
1942                            n.0,
1943                            scale,
1944                            RoundingMode::HalfToEven,
1945                        ))
1946                    }
1947
1948                    #[inline(never)]
1949                    pub fn mg_single(n: Storage, scale: u32) -> Storage {
1950                        Storage(crate::algos::support::mg_divide::div_wide_pow10::<W>(
1951                            n.0,
1952                            scale,
1953                            RoundingMode::HalfToEven,
1954                        ))
1955                    }
1956
1957                    #[inline(never)]
1958                    pub fn newton(n: Storage, scale: u32, table: &NewtonReciprocal) -> Storage {
1959                        Storage(
1960                            crate::algos::support::newton_reciprocal::div_wide_pow10_newton_with::<W>(
1961                                n.0,
1962                                scale,
1963                                RoundingMode::HalfToEven,
1964                                &table.0,
1965                            ),
1966                        )
1967                    }
1968
1969                    /// u128-packed Newton variant. Pre-packs `r` and `pow_scale` at
1970                    /// `precompute` time (cached in the table), then runs the WHOLE
1971                    /// Newton divide entirely on u128 limbs (no per-call pack/unpack
1972                    /// of the cached state, no u128<->u64 transcoding of the operand).
1973                    /// Validity wall: bit-identical to `newton` at every (width,
1974                    /// scale) cell -- verified by the `newton_u64_eq_u128_*` unit
1975                    /// tests in `newton_reciprocal.rs`.
1976                    #[inline(never)]
1977                    pub fn newton_u128(n: Storage, scale: u32, table: &NewtonReciprocal) -> Storage {
1978                        use crate::int::types::traits::BigInt;
1979                        // Match production slicing: the Newton kernel operates
1980                        // on EXACTLY `W::U128_LIMBS` u128 limbs (the storage
1981                        // type's width). Passing the whole 256-limb buffer
1982                        // would inflate the schoolbook product cost on smaller
1983                        // widths — production never does that.
1984                        let mut mag_u128 = [0u128; 256];
1985                        let mag = &mut mag_u128[..W::U128_LIMBS];
1986                        let neg = n.0.mag_into_u128(mag);
1987                        crate::algos::support::newton_reciprocal::newton_pow10_mag_u128_packed(
1988                            mag,
1989                            neg,
1990                            RoundingMode::HalfToEven,
1991                            &table.0,
1992                        );
1993                        Storage(W::from_mag_sign_u128(mag, neg))
1994                    }
1995                }
1996            };
1997        }
1998        shim!(d307, crate::int::types::Int<16>, "x-wide");
1999        // `Int<24>` = 1536-bit storage; matches D462 storage, but ALSO the
2000        // production Work integer used by D230 (Int<12> storage doubles to
2001        // Int<24> for the wide-trig `Work` type). The cells
2002        // `exp_D230_s{172,229}` rescale at this width, so the Newton-vs-MG
2003        // dispatch decision needs `1536`-bit data — hence the dedicated shim
2004        // (the d307/d616/d924/d1232 set skips 1536).
2005        shim!(d462, crate::int::types::Int<24>, "x-wide");
2006        shim!(d616, crate::int::types::Int<32>, "x-wide");
2007        shim!(d924, crate::int::types::Int<48>, "xx-wide");
2008        shim!(d1232, crate::int::types::Int<64>, "xx-wide");
2009        // Int<96>=6144 = D230 Wexp /
2010        // D924 Work. Bench-validated cells extend the Newton-vs-MG
2011        // matrix beyond the 1536-4096 band.
2012        //
2013        // 8192 / 12288 / 16384 / 32768 are NOT exposed here: their
2014        // Newton precompute numerator at the AGM-widened scales
2015        // exceeds the routed Knuth build-max scratch
2016        // (`MAX_SINGLE_LIMBS = 258`), and the integrated-bench picture
2017        // (the atanh diagnosis) suggests MG is the right
2018        // engine at those widths anyway.
2019        shim!(b6144, crate::int::types::Int<96>, "xx-wide");
2020    }
2021
2022    /// `Int<N>` wrapping_neg candidates exposed for the `neg_kernel_ab`
2023    /// dispatch-seam A/B microbench (the wide-tier neg path).
2024    ///
2025    /// Three candidates, all bit-identical:
2026    /// - `neg_fused_split` — the production routed kernel: limb-0
2027    ///   special-cased so the common path (limb 0 != MAX) reduces to
2028    ///   independent `!limb` writes for limbs 1..N with no cross-limb
2029    ///   dependency chain. Wins 1.40x-1.83x at D462/D616/D924/D1232 vs
2030    ///   the previous two-pass form.
2031    /// - `neg_two_pass` — the previous routed shape: NOT loop into
2032    ///   `out[N]`, then a full-width `add_assign_fixed(out, [1, 0, …,
2033    ///   0])` over a second stack array. Retained here for the A/B
2034    ///   seam only.
2035    /// - `neg_fused_open` — single-pass open-coded NOT fused with a
2036    ///   carry-propagating `+1` (dependent carry chain across every
2037    ///   limb). Retained for the A/B; loses to `neg_fused_split` at
2038    ///   wide widths because the dependent chain blocks vectorisation
2039    ///   on the common path.
2040    #[inline(never)]
2041    pub fn neg_fused_split<const N: usize>(
2042        a: crate::int::types::Int<N>,
2043    ) -> crate::int::types::Int<N> {
2044        crate::int::algos::neg::neg_twos_complement::neg_twos_complement::<N>(a)
2045    }
2046    /// Previous routed shape, retained as the `neg_kernel_ab` reference
2047    /// baseline. Bit-identical to `neg_fused_split`.
2048    #[inline(never)]
2049    pub fn neg_two_pass<const N: usize>(a: crate::int::types::Int<N>) -> crate::int::types::Int<N> {
2050        let limbs_in = a.as_limbs();
2051        let mut out = [0u64; N];
2052        let mut i = 0;
2053        while i < N {
2054            out[i] = !limbs_in[i];
2055            i += 1;
2056        }
2057        let mut one = [0u64; N];
2058        if N > 0 {
2059            one[0] = 1;
2060        }
2061        // Inline `add_assign_fixed` so this baseline does not depend on a
2062        // private kernel re-export; bit-identical to the previous
2063        // routed shape.
2064        let mut carry: u64 = 0;
2065        let mut i = 0;
2066        while i < N {
2067            let (s1, c1) = out[i].overflowing_add(one[i]);
2068            let (s2, c2) = s1.overflowing_add(carry);
2069            out[i] = s2;
2070            carry = (c1 as u64) + (c2 as u64);
2071            i += 1;
2072        }
2073        let _ = carry;
2074        crate::int::types::Int::<N>::from_limbs(out)
2075    }
2076    /// Fused open-coded variant: single-pass NOT + carry-propagating
2077    /// `+1`, dependent carry chain across every limb. Retained as a
2078    /// `neg_kernel_ab` candidate; bit-identical to `neg_fused_split`.
2079    #[inline(never)]
2080    pub fn neg_fused_open<const N: usize>(
2081        a: crate::int::types::Int<N>,
2082    ) -> crate::int::types::Int<N> {
2083        let mut out = [0u64; N];
2084        let limbs = a.as_limbs();
2085        let mut carry: u64 = 1;
2086        let mut i = 0;
2087        while i < N {
2088            let (s, c) = (!limbs[i]).overflowing_add(carry);
2089            out[i] = s;
2090            carry = c as u64;
2091            i += 1;
2092        }
2093        let _ = carry;
2094        crate::int::types::Int::<N>::from_limbs(out)
2095    }
2096}
2097mod macros;
2098
2099#[cfg(feature = "cross-scale-ops")]
2100pub mod cross_scale;
2101
2102/// Nightly-gated auto-inferred cross-scale operations. See
2103/// [`mod@cross_scale`] for details.
2104#[cfg(feature = "cross-scale-ops")]
2105pub use crate::cross_scale as cross;
2106
2107// `bitwise` and `num_traits_impls` tests run as Cargo integration
2108// tests under `tests/`. The macro-generated impls themselves are emitted by
2109// `decl_decimal_bitwise!` / `decl_decimal_num_traits_basics!` from
2110// `types/widths.rs`, alongside every other surface.
2111//
2112// The integer layer is unconditional. D38's strict transcendentals use
2113// `Int512` as their guard-digit work integer, so the wide-
2114// integer family must be available in every feature configuration —
2115// not just `feature = "wide"` builds. Compile-time impact is modest:
2116// ~2k LOC of self-contained limb arithmetic plus the const-generic
2117// `Int<N>` / `Uint<N>` monomorphisations.
2118// The integer side of the crate
2119// mirrors the decimal layer's bucket split, all under `int/`:
2120// `int::types` (the `Int<N>`/`Uint<N>` types + named `IntXXXX`
2121// aliases), `int::policy` (algorithm-selection dispatch), and
2122// `int::algos` (width-matched algorithms, including the raw slice limb
2123// primitives in `int::algos::support::limbs`).
2124mod int;
2125mod policy;
2126
2127#[cfg(feature = "serde")]
2128pub use crate::support::serde_helpers;
2129
2130pub use crate::support::error::{ConvertError, ParseError};
2131pub use crate::support::rounding::RoundingMode;
2132pub use crate::types::traits::DecimalConstants;
2133pub use crate::types::traits::Decimal;
2134pub use crate::types::traits::DecimalArithmetic;
2135pub use crate::types::traits::DecimalConvert;
2136pub use crate::types::traits::DecimalTranscendental;
2137pub use crate::types::traits::WidthLE;
2138pub use crate::types::unified::D;
2139
2140#[cfg(feature = "dyn")]
2141pub use crate::types::traits::dyn_decimal::{DecimalWidth, DynDecimal, RawStorage};
2142
2143// D38 — the 128-bit foundation, plus every scale alias D38s0..=D38s37
2144// (scale cap: MAX_SCALE = name - 1).
2145pub use crate::types::widths::{
2146    D38, D38s0, D38s1, D38s2, D38s3, D38s4, D38s5, D38s6, D38s7, D38s8, D38s9, D38s10, D38s11,
2147    D38s12, D38s13, D38s14, D38s15, D38s16, D38s17, D38s18, D38s19, D38s20, D38s21, D38s22, D38s23,
2148    D38s24, D38s25, D38s26, D38s27, D38s28, D38s29, D38s30, D38s31, D38s32, D38s33, D38s34, D38s35,
2149    D38s36, D38s37,
2150};
2151
2152
2153// D18 — 64-bit storage, scale 0..=17 (scale cap: MAX_SCALE = name - 1).
2154pub use crate::types::widths::{
2155    D18, D18s0, D18s1, D18s2, D18s3, D18s4, D18s5, D18s6, D18s7, D18s8, D18s9, D18s10, D18s11,
2156    D18s12, D18s13, D18s14, D18s15, D18s16, D18s17,
2157};
2158
2159// The generic hand-rolled integer `Int<N>` (and unsigned `Uint<N>`) — the
2160// storage backend for D38 (`Int<2>`) and every wide tier. Exported so callers
2161// can name a decimal's storage type, e.g. for `from_bits` / `to_bits`. The
2162// fixed-width aliases (`Int256`, …) are the same types at specific `N`.
2163pub use crate::int::types::{Int, Uint};
2164
2165// Wide-tier scale aliases (D76 and up) are a CURATED convenience subset,
2166// unlike the exhaustive D18/D38 lists above. Every scale in a tier's range
2167// is still valid — write `D76<S>` (etc.) directly for scales without an
2168// alias.
2169
2170// D76 — 256-bit storage, behind the `d76` / `wide` features.
2171#[cfg(any(feature = "d76", feature = "wide"))]
2172pub use crate::types::widths::{
2173    D76, D76s0, D76s1, D76s2, D76s3, D76s4, D76s6, D76s9, D76s12, D76s15, D76s18, D76s20, D76s24,
2174    D76s28, D76s32, D76s35, D76s38, D76s42, D76s48, D76s50, D76s56, D76s64, D76s70, D76s75,
2175};
2176
2177
2178// D153 — 512-bit storage, behind the `d153` / `wide` features.
2179#[cfg(any(feature = "d153", feature = "wide"))]
2180pub use crate::types::widths::{
2181    D153, D153s0, D153s1, D153s2, D153s4, D153s6, D153s9, D153s12, D153s15, D153s18, D153s20,
2182    D153s24, D153s28, D153s32, D153s35, D153s38, D153s50, D153s57, D153s75, D153s76, D153s100,
2183    D153s115, D153s140, D153s150, D153s152,
2184};
2185
2186// D307 — 1024-bit storage, behind the `d307` / `wide` features.
2187#[cfg(any(feature = "d307", feature = "wide"))]
2188pub use crate::types::widths::{
2189    D307, D307s0, D307s1, D307s2, D307s4, D307s6, D307s9, D307s12, D307s15, D307s18, D307s20,
2190    D307s24, D307s28, D307s32, D307s35, D307s38, D307s50, D307s75, D307s100, D307s115, D307s150,
2191    D307s153, D307s200, D307s230, D307s275, D307s300, D307s306,
2192};
2193
2194// ─── New half-width and wider tiers ───────────────────────────────────
2195
2196// D57 — 192-bit storage; half-width between D38 and D76.
2197#[cfg(any(feature = "d57", feature = "wide"))]
2198pub use crate::types::widths::{
2199    D57, D57s0, D57s1, D57s2, D57s4, D57s6, D57s9, D57s12, D57s18, D57s20, D57s24, D57s28, D57s32,
2200    D57s38, D57s42, D57s48, D57s52, D57s56,
2201};
2202
2203// D115 — 384-bit; half-width between D76 and D153.
2204#[cfg(any(feature = "d115", feature = "wide"))]
2205pub use crate::types::widths::{
2206    D115, D115s0, D115s1, D115s4, D115s8, D115s16, D115s24, D115s32, D115s38, D115s50, D115s57,
2207    D115s64, D115s76, D115s90, D115s100, D115s110, D115s114,
2208};
2209
2210// D230 — 768-bit; half-width between D153 and D307.
2211#[cfg(any(feature = "d230", feature = "wide"))]
2212pub use crate::types::widths::{
2213    D230, D230s0, D230s1, D230s6, D230s18, D230s38, D230s57, D230s75, D230s100, D230s115, D230s140,
2214    D230s153, D230s175, D230s200, D230s215, D230s225, D230s229,
2215};
2216
2217// D462 — 1536-bit; half-width between D307 and D616.
2218#[cfg(any(feature = "d462", feature = "x-wide"))]
2219pub use crate::types::widths::{
2220    D462, D462s0, D462s1, D462s18, D462s38, D462s75, D462s115, D462s153, D462s200, D462s230,
2221    D462s275, D462s307, D462s350, D462s400, D462s440, D462s460, D462s461,
2222};
2223
2224// D616 — 2048-bit; new top wide tier. Int2048 / Uint2048 are
2225// already exported above for x-wide / d307 widening; no re-export
2226// here.
2227#[cfg(any(feature = "d616", feature = "x-wide"))]
2228pub use crate::types::widths::{
2229    D616, D616s0, D616s1, D616s38, D616s75, D616s115, D616s153, D616s200, D616s230, D616s275,
2230    D616s308, D616s380, D616s462, D616s500, D616s555, D616s600, D616s615,
2231};
2232
2233// D924 — 3072-bit; half-width between D616 and D1232.
2234#[cfg(any(feature = "d924", feature = "xx-wide"))]
2235pub use crate::types::widths::{
2236    D924, D924s0, D924s1, D924s75, D924s153, D924s230, D924s307, D924s400, D924s461, D924s462,
2237    D924s500, D924s616, D924s700, D924s800, D924s860, D924s900, D924s920, D924s923,
2238};
2239
2240// D1232 — 4096-bit; widest tier shipped.
2241#[cfg(any(feature = "d1232", feature = "xx-wide"))]
2242pub use crate::types::widths::{
2243    D1232, D1232s0, D1232s1, D1232s75, D1232s153, D1232s230, D1232s307, D1232s461, D1232s616,
2244    D1232s700, D1232s800, D1232s900, D1232s924, D1232s1000, D1232s1100, D1232s1180, D1232s1220,
2245    D1232s1230, D1232s1231,
2246};
2247
2248// ─── Construction macros (re-exports + per-scale wrappers) ────────────
2249
2250/// The narrow-tier proc-macros are always available with the
2251/// `macros` feature; the wide-tier proc-macros are additionally
2252/// feature-gated to match their target type's availability.
2253#[cfg(feature = "macros")]
2254pub use decimal_scaled_macros::{d18, d38};
2255
2256#[cfg(all(feature = "macros", any(feature = "d76", feature = "wide")))]
2257pub use decimal_scaled_macros::d76;
2258
2259#[cfg(all(feature = "macros", any(feature = "d153", feature = "wide")))]
2260pub use decimal_scaled_macros::d153;
2261
2262#[cfg(all(
2263    feature = "macros",
2264    any(feature = "d307", feature = "wide", feature = "x-wide")
2265))]
2266pub use decimal_scaled_macros::d307;
2267
2268#[cfg(all(feature = "macros", any(feature = "d57", feature = "wide")))]
2269pub use decimal_scaled_macros::d57;
2270
2271#[cfg(all(feature = "macros", any(feature = "d115", feature = "wide")))]
2272pub use decimal_scaled_macros::d115;
2273
2274#[cfg(all(feature = "macros", any(feature = "d230", feature = "wide")))]
2275pub use decimal_scaled_macros::d230;
2276
2277#[cfg(all(feature = "macros", any(feature = "d462", feature = "x-wide")))]
2278pub use decimal_scaled_macros::d462;
2279
2280#[cfg(all(feature = "macros", any(feature = "d616", feature = "x-wide")))]
2281pub use decimal_scaled_macros::d616;
2282
2283#[cfg(all(feature = "macros", any(feature = "d924", feature = "xx-wide")))]
2284pub use decimal_scaled_macros::d924;
2285
2286#[cfg(all(feature = "macros", any(feature = "d1232", feature = "xx-wide")))]
2287pub use decimal_scaled_macros::d1232;
2288
2289// Per-scale wrappers — curated subset of pre-baked
2290// `<dN>s<SCALE>!` macros that forward to the corresponding
2291// proc-macro with `scale N` added. Long-tail scales remain
2292// reachable via the explicit `, scale N` qualifier.
2293//
2294// Each alias is a tiny `macro_rules!`. We don't generate them
2295// through a nested macro because `macro_rules!` doesn't support
2296// directly emitting another `macro_rules!` without `$$` escapes
2297// that aren't available in stable Rust; explicit per-line
2298// declarations keep things debuggable and only cost ~40 lines.
2299
2300/// `d18s0!(value)` — equivalent to `d18!(value, scale 0)`.
2301#[cfg(feature = "macros")]
2302#[macro_export]
2303macro_rules! d18s0  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d18!($v, scale 0  $(, $($rest)*)?) }; }
2304/// `d18s2!(value)` — equivalent to `d18!(value, scale 2)`.
2305#[cfg(feature = "macros")]
2306#[macro_export]
2307macro_rules! d18s2  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d18!($v, scale 2  $(, $($rest)*)?) }; }
2308/// `d18s4!(value)` — equivalent to `d18!(value, scale 4)`.
2309#[cfg(feature = "macros")]
2310#[macro_export]
2311macro_rules! d18s4  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d18!($v, scale 4  $(, $($rest)*)?) }; }
2312/// `d18s6!(value)` — equivalent to `d18!(value, scale 6)`.
2313#[cfg(feature = "macros")]
2314#[macro_export]
2315macro_rules! d18s6  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d18!($v, scale 6  $(, $($rest)*)?) }; }
2316/// `d18s9!(value)` — equivalent to `d18!(value, scale 9)`.
2317#[cfg(feature = "macros")]
2318#[macro_export]
2319macro_rules! d18s9  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d18!($v, scale 9  $(, $($rest)*)?) }; }
2320/// `d18s12!(value)` — equivalent to `d18!(value, scale 12)`.
2321#[cfg(feature = "macros")]
2322#[macro_export]
2323macro_rules! d18s12 { ($v:tt $(, $($rest:tt)*)?) => { $crate::d18!($v, scale 12 $(, $($rest)*)?) }; }
2324
2325// D38 curated scales.
2326/// `d38s0!(value)` — equivalent to `d38!(value, scale 0)`.
2327#[cfg(feature = "macros")]
2328#[macro_export]
2329macro_rules! d38s0  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d38!($v, scale 0  $(, $($rest)*)?) }; }
2330/// `d38s2!(value)` — equivalent to `d38!(value, scale 2)`.
2331#[cfg(feature = "macros")]
2332#[macro_export]
2333macro_rules! d38s2  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d38!($v, scale 2  $(, $($rest)*)?) }; }
2334/// `d38s4!(value)` — equivalent to `d38!(value, scale 4)`.
2335#[cfg(feature = "macros")]
2336#[macro_export]
2337macro_rules! d38s4  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d38!($v, scale 4  $(, $($rest)*)?) }; }
2338/// `d38s6!(value)` — equivalent to `d38!(value, scale 6)`.
2339#[cfg(feature = "macros")]
2340#[macro_export]
2341macro_rules! d38s6  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d38!($v, scale 6  $(, $($rest)*)?) }; }
2342/// `d38s8!(value)` — equivalent to `d38!(value, scale 8)`.
2343#[cfg(feature = "macros")]
2344#[macro_export]
2345macro_rules! d38s8  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d38!($v, scale 8  $(, $($rest)*)?) }; }
2346/// `d38s9!(value)` — equivalent to `d38!(value, scale 9)`.
2347#[cfg(feature = "macros")]
2348#[macro_export]
2349macro_rules! d38s9  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d38!($v, scale 9  $(, $($rest)*)?) }; }
2350/// `d38s12!(value)` — equivalent to `d38!(value, scale 12)`.
2351#[cfg(feature = "macros")]
2352#[macro_export]
2353macro_rules! d38s12 { ($v:tt $(, $($rest:tt)*)?) => { $crate::d38!($v, scale 12 $(, $($rest)*)?) }; }
2354/// `d38s15!(value)` — equivalent to `d38!(value, scale 15)`.
2355#[cfg(feature = "macros")]
2356#[macro_export]
2357macro_rules! d38s15 { ($v:tt $(, $($rest:tt)*)?) => { $crate::d38!($v, scale 15 $(, $($rest)*)?) }; }
2358/// `d38s18!(value)` — equivalent to `d38!(value, scale 18)`.
2359#[cfg(feature = "macros")]
2360#[macro_export]
2361macro_rules! d38s18 { ($v:tt $(, $($rest:tt)*)?) => { $crate::d38!($v, scale 18 $(, $($rest)*)?) }; }
2362/// `d38s24!(value)` — equivalent to `d38!(value, scale 24)`.
2363#[cfg(feature = "macros")]
2364#[macro_export]
2365macro_rules! d38s24 { ($v:tt $(, $($rest:tt)*)?) => { $crate::d38!($v, scale 24 $(, $($rest)*)?) }; }
2366/// `d38s35!(value)` — equivalent to `d38!(value, scale 35)`.
2367#[cfg(feature = "macros")]
2368#[macro_export]
2369macro_rules! d38s35 { ($v:tt $(, $($rest:tt)*)?) => { $crate::d38!($v, scale 35 $(, $($rest)*)?) }; }
2370
2371// D76 curated scales.
2372/// `d76s0!(value)` — equivalent to `d76!(value, scale 0)`.
2373#[cfg(all(feature = "macros", any(feature = "d76", feature = "wide")))]
2374#[macro_export]
2375macro_rules! d76s0  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d76!($v, scale 0  $(, $($rest)*)?) }; }
2376/// `d76s2!(value)` — equivalent to `d76!(value, scale 2)`.
2377#[cfg(all(feature = "macros", any(feature = "d76", feature = "wide")))]
2378#[macro_export]
2379macro_rules! d76s2  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d76!($v, scale 2  $(, $($rest)*)?) }; }
2380/// `d76s6!(value)` — equivalent to `d76!(value, scale 6)`.
2381#[cfg(all(feature = "macros", any(feature = "d76", feature = "wide")))]
2382#[macro_export]
2383macro_rules! d76s6  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d76!($v, scale 6  $(, $($rest)*)?) }; }
2384/// `d76s12!(value)` — equivalent to `d76!(value, scale 12)`.
2385#[cfg(all(feature = "macros", any(feature = "d76", feature = "wide")))]
2386#[macro_export]
2387macro_rules! d76s12 { ($v:tt $(, $($rest:tt)*)?) => { $crate::d76!($v, scale 12 $(, $($rest)*)?) }; }
2388/// `d76s18!(value)` — equivalent to `d76!(value, scale 18)`.
2389#[cfg(all(feature = "macros", any(feature = "d76", feature = "wide")))]
2390#[macro_export]
2391macro_rules! d76s18 { ($v:tt $(, $($rest:tt)*)?) => { $crate::d76!($v, scale 18 $(, $($rest)*)?) }; }
2392/// `d76s35!(value)` — equivalent to `d76!(value, scale 35)`.
2393#[cfg(all(feature = "macros", any(feature = "d76", feature = "wide")))]
2394#[macro_export]
2395macro_rules! d76s35 { ($v:tt $(, $($rest:tt)*)?) => { $crate::d76!($v, scale 35 $(, $($rest)*)?) }; }
2396/// `d76s50!(value)` — equivalent to `d76!(value, scale 50)`.
2397#[cfg(all(feature = "macros", any(feature = "d76", feature = "wide")))]
2398#[macro_export]
2399macro_rules! d76s50 { ($v:tt $(, $($rest:tt)*)?) => { $crate::d76!($v, scale 50 $(, $($rest)*)?) }; }
2400
2401// D153 curated scales.
2402/// `d153s0!(value)` — equivalent to `d153!(value, scale 0)`.
2403#[cfg(all(feature = "macros", any(feature = "d153", feature = "wide")))]
2404#[macro_export]
2405macro_rules! d153s0   { ($v:tt $(, $($rest:tt)*)?) => { $crate::d153!($v, scale 0   $(, $($rest)*)?) }; }
2406/// `d153s35!(value)` — equivalent to `d153!(value, scale 35)`.
2407#[cfg(all(feature = "macros", any(feature = "d153", feature = "wide")))]
2408#[macro_export]
2409macro_rules! d153s35  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d153!($v, scale 35  $(, $($rest)*)?) }; }
2410/// `d153s75!(value)` — equivalent to `d153!(value, scale 75)`.
2411#[cfg(all(feature = "macros", any(feature = "d153", feature = "wide")))]
2412#[macro_export]
2413macro_rules! d153s75  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d153!($v, scale 75  $(, $($rest)*)?) }; }
2414/// `d153s150!(value)` — equivalent to `d153!(value, scale 150)`.
2415#[cfg(all(feature = "macros", any(feature = "d153", feature = "wide")))]
2416#[macro_export]
2417macro_rules! d153s150 { ($v:tt $(, $($rest:tt)*)?) => { $crate::d153!($v, scale 150 $(, $($rest)*)?) }; }
2418
2419// D307 curated scales.
2420/// `d307s0!(value)` — equivalent to `d307!(value, scale 0)`.
2421#[cfg(all(
2422    feature = "macros",
2423    any(feature = "d307", feature = "wide", feature = "x-wide")
2424))]
2425#[macro_export]
2426macro_rules! d307s0   { ($v:tt $(, $($rest:tt)*)?) => { $crate::d307!($v, scale 0   $(, $($rest)*)?) }; }
2427/// `d307s35!(value)` — equivalent to `d307!(value, scale 35)`.
2428#[cfg(all(
2429    feature = "macros",
2430    any(feature = "d307", feature = "wide", feature = "x-wide")
2431))]
2432#[macro_export]
2433macro_rules! d307s35  { ($v:tt $(, $($rest:tt)*)?) => { $crate::d307!($v, scale 35  $(, $($rest)*)?) }; }
2434/// `d307s150!(value)` — equivalent to `d307!(value, scale 150)`.
2435#[cfg(all(
2436    feature = "macros",
2437    any(feature = "d307", feature = "wide", feature = "x-wide")
2438))]
2439#[macro_export]
2440macro_rules! d307s150 { ($v:tt $(, $($rest:tt)*)?) => { $crate::d307!($v, scale 150 $(, $($rest)*)?) }; }
2441/// `d307s300!(value)` — equivalent to `d307!(value, scale 300)`.
2442#[cfg(all(
2443    feature = "macros",
2444    any(feature = "d307", feature = "wide", feature = "x-wide")
2445))]
2446#[macro_export]
2447macro_rules! d307s300 { ($v:tt $(, $($rest:tt)*)?) => { $crate::d307!($v, scale 300 $(, $($rest)*)?) }; }