Skip to main content

decimal_scaled/types/
trig.rs

1// SPDX-FileCopyrightText: 2026 John Moxley
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Trigonometric, hyperbolic, and angle-conversion methods for [`D38`].
5//!
6//! # Surface
7//!
8//! Fifteen mathematical functions:
9//!
10//! - **Forward trig (radians input):** [`D38::sin`] / [`D38::cos`] /
11//! [`D38::tan`].
12//! - **Inverse trig (returns radians):** [`D38::asin`] / [`D38::acos`]
13//! / [`D38::atan`] / [`D38::atan2`].
14//! - **Hyperbolic:** [`D38::sinh`] / [`D38::cosh`] / [`D38::tanh`] /
15//! [`D38::asinh`] / [`D38::acosh`] / [`D38::atanh`].
16//! - **Angle conversions:** [`D38::to_degrees`] / [`D38::to_radians`].
17//!
18//! # The four-variant matrix
19//!
20//! Each function ships with four entry points so a single name covers
21//! every (precision × rounding) combination the surface needs:
22//!
23//! | Method            | Guard width    | Rounding mode               |
24//! |-------------------|----------------|------------------------------|
25//! | `<fn>_strict`     | crate default  | crate default ([`RoundingMode::HalfToEven`] unless a `rounding-*` feature is set) |
26//! | `<fn>_strict_with`| crate default  | caller-supplied              |
27//! | `<fn>_approx`     | caller-chosen  | crate default               |
28//! | `<fn>_approx_with`| caller-chosen  | caller-supplied              |
29//!
30//! All four variants are integer-only, `no_std`-compatible, and
31//! correctly rounded under the selected mode. Without the `strict`
32//! feature, the plain `<fn>` is an f64-bridge instead.
33//!
34//! # Layering
35//!
36//! Every public method on this file is a one-line delegate into
37//! `policy::trig`. The correctly-rounded kernels
38//! (`sin_fixed`, `atan_fixed`, `atan2_kernel`, `to_fixed`, `wide_pi`,
39//! `wide_half_pi`, `small_x_linear_threshold`, and every per-method
40//! `*_strict` / `*_with` `Fixed`-shape function for sin / cos / tan /
41//! atan / asin / acos / atan2 / sinh / cosh / tanh / asinh / acosh /
42//! atanh / to_degrees / to_radians) live in
43//! [`crate::algos::trig::trig_series_2limb`]. This file is a typed-shell
44//! surface; there are zero `crate::algos::*` or
45//! `crate::algos::support::fixed::*` references in it.
46//!
47//! [`RoundingMode::HalfToEven`]: crate::RoundingMode::HalfToEven
48//!
49//! # `atan2` signature
50//!
51//! `f64::atan2(self, other)` treats `self` as `y` and `other` as `x`.
52//! This module matches that signature exactly so generic numeric code
53//! calling `y.atan2(x)` works with `T = D38`.
54
55use crate::types::log_exp::STRICT_GUARD;
56
57impl<const SCALE: u32> crate::D<crate::int::types::Int<2>, SCALE> {
58    // ── Plain dispatchers (strict-feature) ────────────────────────
59
60    #[cfg(all(feature = "strict", not(feature = "fast")))]
61    #[inline]
62    #[must_use]
63    pub fn sin(self) -> Self {
64        self.sin_strict()
65    }
66
67    #[cfg(all(feature = "strict", not(feature = "fast")))]
68    #[inline]
69    #[must_use]
70    pub fn cos(self) -> Self {
71        self.cos_strict()
72    }
73
74    #[cfg(all(feature = "strict", not(feature = "fast")))]
75    #[inline]
76    #[must_use]
77    pub fn tan(self) -> Self {
78        self.tan_strict()
79    }
80
81    #[cfg(all(feature = "strict", not(feature = "fast")))]
82    #[inline]
83    #[must_use]
84    pub fn asin(self) -> Self {
85        self.asin_strict()
86    }
87
88    #[cfg(all(feature = "strict", not(feature = "fast")))]
89    #[inline]
90    #[must_use]
91    pub fn acos(self) -> Self {
92        self.acos_strict()
93    }
94
95    #[cfg(all(feature = "strict", not(feature = "fast")))]
96    #[inline]
97    #[must_use]
98    pub fn atan(self) -> Self {
99        self.atan_strict()
100    }
101
102    #[cfg(all(feature = "strict", not(feature = "fast")))]
103    #[inline]
104    #[must_use]
105    pub fn atan2(self, other: Self) -> Self {
106        self.atan2_strict(other)
107    }
108
109    #[cfg(all(feature = "strict", not(feature = "fast")))]
110    #[inline]
111    #[must_use]
112    pub fn sinh(self) -> Self {
113        self.sinh_strict()
114    }
115
116    #[cfg(all(feature = "strict", not(feature = "fast")))]
117    #[inline]
118    #[must_use]
119    pub fn cosh(self) -> Self {
120        self.cosh_strict()
121    }
122
123    #[cfg(all(feature = "strict", not(feature = "fast")))]
124    #[inline]
125    #[must_use]
126    pub fn tanh(self) -> Self {
127        self.tanh_strict()
128    }
129
130    #[cfg(all(feature = "strict", not(feature = "fast")))]
131    #[inline]
132    #[must_use]
133    pub fn asinh(self) -> Self {
134        self.asinh_strict()
135    }
136
137    #[cfg(all(feature = "strict", not(feature = "fast")))]
138    #[inline]
139    #[must_use]
140    pub fn acosh(self) -> Self {
141        self.acosh_strict()
142    }
143
144    #[cfg(all(feature = "strict", not(feature = "fast")))]
145    #[inline]
146    #[must_use]
147    pub fn atanh(self) -> Self {
148        self.atanh_strict()
149    }
150
151    #[cfg(all(feature = "strict", not(feature = "fast")))]
152    #[inline]
153    #[must_use]
154    pub fn to_degrees(self) -> Self {
155        self.to_degrees_strict()
156    }
157
158    #[cfg(all(feature = "strict", not(feature = "fast")))]
159    #[inline]
160    #[must_use]
161    pub fn to_radians(self) -> Self {
162        self.to_radians_strict()
163    }
164
165    // ── Forward trig (one-line policy delegates) ──────────────────
166
167    /// Sine of `self` (radians). Correctly rounded.
168    #[inline]
169    #[must_use]
170    pub fn sin_strict(self) -> Self {
171        self.sin_strict_with(crate::support::rounding::DEFAULT_ROUNDING_MODE)
172    }
173
174    #[inline]
175    #[must_use]
176    pub fn sin_strict_with(self, mode: crate::support::rounding::RoundingMode) -> Self {
177        Self::from_bits(crate::policy::trig::sin_dispatch::<_, SCALE>(self.to_bits(), mode))
178    }
179
180    #[inline]
181    #[must_use]
182    pub fn sin_approx(self, working_digits: u32) -> Self {
183        self.sin_approx_with(
184            working_digits,
185            crate::support::rounding::DEFAULT_ROUNDING_MODE,
186        )
187    }
188
189    #[inline]
190    #[must_use]
191    pub fn sin_approx_with(
192        self,
193        working_digits: u32,
194        mode: crate::support::rounding::RoundingMode,
195    ) -> Self {
196        if working_digits == STRICT_GUARD {
197            return self.sin_strict_with(mode);
198        }
199        Self::from_bits(crate::policy::trig::sin_dispatch_with::<_, SCALE>(self.to_bits(), working_digits, mode))
200    }
201
202    /// Cosine of `self` (radians). `cos(x) = sin(x + π/2)`.
203    #[inline]
204    #[must_use]
205    pub fn cos_strict(self) -> Self {
206        self.cos_strict_with(crate::support::rounding::DEFAULT_ROUNDING_MODE)
207    }
208
209    #[inline]
210    #[must_use]
211    pub fn cos_strict_with(self, mode: crate::support::rounding::RoundingMode) -> Self {
212        Self::from_bits(crate::policy::trig::cos_dispatch::<_, SCALE>(self.to_bits(), mode))
213    }
214
215    #[inline]
216    #[must_use]
217    pub fn cos_approx(self, working_digits: u32) -> Self {
218        self.cos_approx_with(
219            working_digits,
220            crate::support::rounding::DEFAULT_ROUNDING_MODE,
221        )
222    }
223
224    #[inline]
225    #[must_use]
226    pub fn cos_approx_with(
227        self,
228        working_digits: u32,
229        mode: crate::support::rounding::RoundingMode,
230    ) -> Self {
231        if working_digits == STRICT_GUARD {
232            return self.cos_strict_with(mode);
233        }
234        Self::from_bits(crate::policy::trig::cos_dispatch_with::<_, SCALE>(self.to_bits(), working_digits, mode))
235    }
236
237    /// Tangent. Panics if `cos(self)` is zero.
238    #[inline]
239    #[must_use]
240    pub fn tan_strict(self) -> Self {
241        self.tan_strict_with(crate::support::rounding::DEFAULT_ROUNDING_MODE)
242    }
243
244    #[inline]
245    #[must_use]
246    pub fn tan_strict_with(self, mode: crate::support::rounding::RoundingMode) -> Self {
247        Self::from_bits(crate::policy::trig::tan_dispatch::<_, SCALE>(self.to_bits(), mode))
248    }
249
250    #[inline]
251    #[must_use]
252    pub fn tan_approx(self, working_digits: u32) -> Self {
253        self.tan_approx_with(
254            working_digits,
255            crate::support::rounding::DEFAULT_ROUNDING_MODE,
256        )
257    }
258
259    #[inline]
260    #[must_use]
261    pub fn tan_approx_with(
262        self,
263        working_digits: u32,
264        mode: crate::support::rounding::RoundingMode,
265    ) -> Self {
266        if working_digits == STRICT_GUARD {
267            return self.tan_strict_with(mode);
268        }
269        Self::from_bits(crate::policy::trig::tan_dispatch_with::<_, SCALE>(self.to_bits(), working_digits, mode))
270    }
271
272    /// Arctangent.
273    #[inline]
274    #[must_use]
275    pub fn atan_strict(self) -> Self {
276        self.atan_strict_with(crate::support::rounding::DEFAULT_ROUNDING_MODE)
277    }
278
279    #[inline]
280    #[must_use]
281    pub fn atan_strict_with(self, mode: crate::support::rounding::RoundingMode) -> Self {
282        Self::from_bits(crate::policy::trig::atan_dispatch::<_, SCALE>(self.to_bits(), mode))
283    }
284
285    #[inline]
286    #[must_use]
287    pub fn atan_approx(self, working_digits: u32) -> Self {
288        self.atan_approx_with(
289            working_digits,
290            crate::support::rounding::DEFAULT_ROUNDING_MODE,
291        )
292    }
293
294    #[inline]
295    #[must_use]
296    pub fn atan_approx_with(
297        self,
298        working_digits: u32,
299        mode: crate::support::rounding::RoundingMode,
300    ) -> Self {
301        if working_digits == STRICT_GUARD {
302            return self.atan_strict_with(mode);
303        }
304        Self::from_bits(crate::policy::trig::atan_dispatch_with::<_, SCALE>(self.to_bits(), working_digits, mode))
305    }
306
307    /// Arcsine. Panics if `|self| > 1`.
308    #[inline]
309    #[must_use]
310    pub fn asin_strict(self) -> Self {
311        self.asin_strict_with(crate::support::rounding::DEFAULT_ROUNDING_MODE)
312    }
313
314    #[inline]
315    #[must_use]
316    pub fn asin_strict_with(self, mode: crate::support::rounding::RoundingMode) -> Self {
317        Self::from_bits(crate::policy::trig::asin_dispatch::<_, SCALE>(self.to_bits(), mode))
318    }
319
320    #[inline]
321    #[must_use]
322    pub fn asin_approx(self, working_digits: u32) -> Self {
323        self.asin_approx_with(
324            working_digits,
325            crate::support::rounding::DEFAULT_ROUNDING_MODE,
326        )
327    }
328
329    #[inline]
330    #[must_use]
331    pub fn asin_approx_with(
332        self,
333        working_digits: u32,
334        mode: crate::support::rounding::RoundingMode,
335    ) -> Self {
336        if working_digits == STRICT_GUARD {
337            return self.asin_strict_with(mode);
338        }
339        Self::from_bits(crate::policy::trig::asin_dispatch_with::<_, SCALE>(self.to_bits(), working_digits, mode))
340    }
341
342    /// Arccosine. Panics if `|self| > 1`.
343    #[inline]
344    #[must_use]
345    pub fn acos_strict(self) -> Self {
346        self.acos_strict_with(crate::support::rounding::DEFAULT_ROUNDING_MODE)
347    }
348
349    #[inline]
350    #[must_use]
351    pub fn acos_strict_with(self, mode: crate::support::rounding::RoundingMode) -> Self {
352        Self::from_bits(crate::policy::trig::acos_dispatch::<_, SCALE>(self.to_bits(), mode))
353    }
354
355    #[inline]
356    #[must_use]
357    pub fn acos_approx(self, working_digits: u32) -> Self {
358        self.acos_approx_with(
359            working_digits,
360            crate::support::rounding::DEFAULT_ROUNDING_MODE,
361        )
362    }
363
364    #[inline]
365    #[must_use]
366    pub fn acos_approx_with(
367        self,
368        working_digits: u32,
369        mode: crate::support::rounding::RoundingMode,
370    ) -> Self {
371        if working_digits == STRICT_GUARD {
372            return self.acos_strict_with(mode);
373        }
374        Self::from_bits(crate::policy::trig::acos_dispatch_with::<_, SCALE>(self.to_bits(), working_digits, mode))
375    }
376
377    /// Four-quadrant arctangent of `self` (`y`) and `other` (`x`).
378    #[inline]
379    #[must_use]
380    pub fn atan2_strict(self, other: Self) -> Self {
381        self.atan2_strict_with(other, crate::support::rounding::DEFAULT_ROUNDING_MODE)
382    }
383
384    #[inline]
385    #[must_use]
386    pub fn atan2_strict_with(
387        self,
388        other: Self,
389        mode: crate::support::rounding::RoundingMode,
390    ) -> Self {
391        Self::from_bits(crate::policy::trig::atan2_dispatch::<_, SCALE>(self.to_bits(), other.to_bits(), mode))
392    }
393
394    #[inline]
395    #[must_use]
396    pub fn atan2_approx(self, other: Self, working_digits: u32) -> Self {
397        self.atan2_approx_with(
398            other,
399            working_digits,
400            crate::support::rounding::DEFAULT_ROUNDING_MODE,
401        )
402    }
403
404    #[inline]
405    #[must_use]
406    pub fn atan2_approx_with(
407        self,
408        other: Self,
409        working_digits: u32,
410        mode: crate::support::rounding::RoundingMode,
411    ) -> Self {
412        if working_digits == STRICT_GUARD {
413            return self.atan2_strict_with(other, mode);
414        }
415        Self::from_bits(crate::policy::trig::atan2_dispatch_with::<_, SCALE>(self.to_bits(), other.to_bits(), working_digits, mode))
416    }
417
418    // ── Hyperbolic family (one-line policy delegates) ─────────────
419
420    /// Hyperbolic sine. Correctly rounded.
421    #[inline]
422    #[must_use]
423    pub fn sinh_strict(self) -> Self {
424        self.sinh_strict_with(crate::support::rounding::DEFAULT_ROUNDING_MODE)
425    }
426
427    #[inline]
428    #[must_use]
429    pub fn sinh_strict_with(self, mode: crate::support::rounding::RoundingMode) -> Self {
430        Self::from_bits(crate::policy::trig::sinh_dispatch::<_, SCALE>(self.to_bits(), mode))
431    }
432
433    #[inline]
434    #[must_use]
435    pub fn sinh_approx(self, working_digits: u32) -> Self {
436        self.sinh_approx_with(
437            working_digits,
438            crate::support::rounding::DEFAULT_ROUNDING_MODE,
439        )
440    }
441
442    #[inline]
443    #[must_use]
444    pub fn sinh_approx_with(
445        self,
446        working_digits: u32,
447        mode: crate::support::rounding::RoundingMode,
448    ) -> Self {
449        if working_digits == STRICT_GUARD {
450            return self.sinh_strict_with(mode);
451        }
452        Self::from_bits(crate::policy::trig::sinh_dispatch_with::<_, SCALE>(self.to_bits(), working_digits, mode))
453    }
454
455    /// Hyperbolic cosine.
456    #[inline]
457    #[must_use]
458    pub fn cosh_strict(self) -> Self {
459        self.cosh_strict_with(crate::support::rounding::DEFAULT_ROUNDING_MODE)
460    }
461
462    #[inline]
463    #[must_use]
464    pub fn cosh_strict_with(self, mode: crate::support::rounding::RoundingMode) -> Self {
465        Self::from_bits(crate::policy::trig::cosh_dispatch::<_, SCALE>(self.to_bits(), mode))
466    }
467
468    #[inline]
469    #[must_use]
470    pub fn cosh_approx(self, working_digits: u32) -> Self {
471        self.cosh_approx_with(
472            working_digits,
473            crate::support::rounding::DEFAULT_ROUNDING_MODE,
474        )
475    }
476
477    #[inline]
478    #[must_use]
479    pub fn cosh_approx_with(
480        self,
481        working_digits: u32,
482        mode: crate::support::rounding::RoundingMode,
483    ) -> Self {
484        if working_digits == STRICT_GUARD {
485            return self.cosh_strict_with(mode);
486        }
487        Self::from_bits(crate::policy::trig::cosh_dispatch_with::<_, SCALE>(self.to_bits(), working_digits, mode))
488    }
489
490    /// Hyperbolic tangent.
491    #[inline]
492    #[must_use]
493    pub fn tanh_strict(self) -> Self {
494        self.tanh_strict_with(crate::support::rounding::DEFAULT_ROUNDING_MODE)
495    }
496
497    #[inline]
498    #[must_use]
499    pub fn tanh_strict_with(self, mode: crate::support::rounding::RoundingMode) -> Self {
500        Self::from_bits(crate::policy::trig::tanh_dispatch::<_, SCALE>(self.to_bits(), mode))
501    }
502
503    #[inline]
504    #[must_use]
505    pub fn tanh_approx(self, working_digits: u32) -> Self {
506        self.tanh_approx_with(
507            working_digits,
508            crate::support::rounding::DEFAULT_ROUNDING_MODE,
509        )
510    }
511
512    #[inline]
513    #[must_use]
514    pub fn tanh_approx_with(
515        self,
516        working_digits: u32,
517        mode: crate::support::rounding::RoundingMode,
518    ) -> Self {
519        if working_digits == STRICT_GUARD {
520            return self.tanh_strict_with(mode);
521        }
522        Self::from_bits(crate::policy::trig::tanh_dispatch_with::<_, SCALE>(self.to_bits(), working_digits, mode))
523    }
524
525    /// Inverse hyperbolic sine. `asinh(x) = sign · ln(|x| + √(x²+1))`.
526    #[inline]
527    #[must_use]
528    pub fn asinh_strict(self) -> Self {
529        self.asinh_strict_with(crate::support::rounding::DEFAULT_ROUNDING_MODE)
530    }
531
532    #[inline]
533    #[must_use]
534    pub fn asinh_strict_with(self, mode: crate::support::rounding::RoundingMode) -> Self {
535        Self::from_bits(crate::policy::trig::asinh_dispatch::<_, SCALE>(self.to_bits(), mode))
536    }
537
538    #[inline]
539    #[must_use]
540    pub fn asinh_approx(self, working_digits: u32) -> Self {
541        self.asinh_approx_with(
542            working_digits,
543            crate::support::rounding::DEFAULT_ROUNDING_MODE,
544        )
545    }
546
547    #[inline]
548    #[must_use]
549    pub fn asinh_approx_with(
550        self,
551        working_digits: u32,
552        mode: crate::support::rounding::RoundingMode,
553    ) -> Self {
554        if working_digits == STRICT_GUARD {
555            return self.asinh_strict_with(mode);
556        }
557        Self::from_bits(crate::policy::trig::asinh_dispatch_with::<_, SCALE>(self.to_bits(), working_digits, mode))
558    }
559
560    /// Inverse hyperbolic cosine. Panics if `self < 1`.
561    #[inline]
562    #[must_use]
563    pub fn acosh_strict(self) -> Self {
564        self.acosh_strict_with(crate::support::rounding::DEFAULT_ROUNDING_MODE)
565    }
566
567    #[inline]
568    #[must_use]
569    pub fn acosh_strict_with(self, mode: crate::support::rounding::RoundingMode) -> Self {
570        Self::from_bits(crate::policy::trig::acosh_dispatch::<_, SCALE>(self.to_bits(), mode))
571    }
572
573    #[inline]
574    #[must_use]
575    pub fn acosh_approx(self, working_digits: u32) -> Self {
576        self.acosh_approx_with(
577            working_digits,
578            crate::support::rounding::DEFAULT_ROUNDING_MODE,
579        )
580    }
581
582    #[inline]
583    #[must_use]
584    pub fn acosh_approx_with(
585        self,
586        working_digits: u32,
587        mode: crate::support::rounding::RoundingMode,
588    ) -> Self {
589        if working_digits == STRICT_GUARD {
590            return self.acosh_strict_with(mode);
591        }
592        Self::from_bits(crate::policy::trig::acosh_dispatch_with::<_, SCALE>(self.to_bits(), working_digits, mode))
593    }
594
595    /// Inverse hyperbolic tangent. Panics if `|self| >= 1`.
596    #[inline]
597    #[must_use]
598    pub fn atanh_strict(self) -> Self {
599        self.atanh_strict_with(crate::support::rounding::DEFAULT_ROUNDING_MODE)
600    }
601
602    #[inline]
603    #[must_use]
604    pub fn atanh_strict_with(self, mode: crate::support::rounding::RoundingMode) -> Self {
605        Self::from_bits(crate::policy::trig::atanh_dispatch::<_, SCALE>(self.to_bits(), mode))
606    }
607
608    #[inline]
609    #[must_use]
610    pub fn atanh_approx(self, working_digits: u32) -> Self {
611        self.atanh_approx_with(
612            working_digits,
613            crate::support::rounding::DEFAULT_ROUNDING_MODE,
614        )
615    }
616
617    #[inline]
618    #[must_use]
619    pub fn atanh_approx_with(
620        self,
621        working_digits: u32,
622        mode: crate::support::rounding::RoundingMode,
623    ) -> Self {
624        if working_digits == STRICT_GUARD {
625            return self.atanh_strict_with(mode);
626        }
627        Self::from_bits(crate::policy::trig::atanh_dispatch_with::<_, SCALE>(self.to_bits(), working_digits, mode))
628    }
629
630    // ── Angle conversions (one-line policy delegates) ─────────────
631
632    /// Convert radians to degrees: `self · (180 / π)`.
633    #[inline]
634    #[must_use]
635    pub fn to_degrees_strict(self) -> Self {
636        self.to_degrees_strict_with(crate::support::rounding::DEFAULT_ROUNDING_MODE)
637    }
638
639    #[inline]
640    #[must_use]
641    pub fn to_degrees_strict_with(self, mode: crate::support::rounding::RoundingMode) -> Self {
642        Self::from_bits(crate::policy::trig::to_degrees_dispatch::<_, SCALE>(self.to_bits(), mode))
643    }
644
645    #[inline]
646    #[must_use]
647    pub fn to_degrees_approx(self, working_digits: u32) -> Self {
648        self.to_degrees_approx_with(
649            working_digits,
650            crate::support::rounding::DEFAULT_ROUNDING_MODE,
651        )
652    }
653
654    #[inline]
655    #[must_use]
656    pub fn to_degrees_approx_with(
657        self,
658        working_digits: u32,
659        mode: crate::support::rounding::RoundingMode,
660    ) -> Self {
661        if working_digits == STRICT_GUARD {
662            return self.to_degrees_strict_with(mode);
663        }
664        Self::from_bits(crate::policy::trig::to_degrees_dispatch_with::<_, SCALE>(self.to_bits(), working_digits, mode))
665    }
666
667    /// Convert degrees to radians: `self · (π / 180)`.
668    #[inline]
669    #[must_use]
670    pub fn to_radians_strict(self) -> Self {
671        self.to_radians_strict_with(crate::support::rounding::DEFAULT_ROUNDING_MODE)
672    }
673
674    #[inline]
675    #[must_use]
676    pub fn to_radians_strict_with(self, mode: crate::support::rounding::RoundingMode) -> Self {
677        Self::from_bits(crate::policy::trig::to_radians_dispatch::<_, SCALE>(self.to_bits(), mode))
678    }
679
680    #[inline]
681    #[must_use]
682    pub fn to_radians_approx(self, working_digits: u32) -> Self {
683        self.to_radians_approx_with(
684            working_digits,
685            crate::support::rounding::DEFAULT_ROUNDING_MODE,
686        )
687    }
688
689    #[inline]
690    #[must_use]
691    pub fn to_radians_approx_with(
692        self,
693        working_digits: u32,
694        mode: crate::support::rounding::RoundingMode,
695    ) -> Self {
696        if working_digits == STRICT_GUARD {
697            return self.to_radians_strict_with(mode);
698        }
699        Self::from_bits(crate::policy::trig::to_radians_dispatch_with::<_, SCALE>(self.to_bits(), working_digits, mode))
700    }
701}