simple_soft_float/
lib.rs

1// SPDX-License-Identifier: LGPL-2.1-or-later
2// See Notices.txt for copyright information
3
4#![allow(clippy::unneeded_field_pattern)]
5#![allow(clippy::too_many_arguments)]
6#![deny(missing_docs)]
7
8//! Soft-float library that intends to be a straightforward reference implementation of IEEE 754
9
10use algebraics::prelude::*;
11use bitflags::bitflags;
12use num_bigint::BigInt;
13use num_bigint::BigUint;
14use num_integer::Integer;
15use num_rational::Ratio;
16use num_traits::FromPrimitive;
17use num_traits::NumAssign;
18use num_traits::NumAssignRef;
19use num_traits::NumRef;
20use num_traits::ToPrimitive;
21use num_traits::Unsigned;
22use std::cmp::Ordering;
23use std::error::Error;
24use std::fmt;
25use std::ops::Add;
26use std::ops::AddAssign;
27use std::ops::BitAnd;
28use std::ops::BitAndAssign;
29use std::ops::BitOr;
30use std::ops::BitOrAssign;
31use std::ops::BitXor;
32use std::ops::BitXorAssign;
33use std::ops::Deref;
34use std::ops::DerefMut;
35use std::ops::Div;
36use std::ops::DivAssign;
37use std::ops::Mul;
38use std::ops::MulAssign;
39use std::ops::Neg;
40use std::ops::Shl;
41use std::ops::ShlAssign;
42use std::ops::Shr;
43use std::ops::ShrAssign;
44use std::ops::Sub;
45use std::ops::SubAssign;
46
47#[cfg(feature = "python")]
48use crate::python::PyPlatformProperties;
49#[cfg(feature = "python")]
50use crate::python::ToPythonRepr;
51#[cfg(feature = "python")]
52use pyo3::prelude::*;
53#[cfg(feature = "python")]
54use std::borrow::Cow;
55
56#[macro_use]
57mod python_macros;
58mod python;
59
60#[cfg(test)]
61mod test_cases;
62
63python_enum! {
64    #[pyenum(module = simple_soft_float, repr = u8, test_fn = test_sign_enum)]
65    /// sign of floating-point number
66    pub enum Sign {
67        /// + sign
68        Positive = 0,
69        /// - sign
70        Negative = 1,
71    }
72}
73
74impl Neg for Sign {
75    type Output = Self;
76    fn neg(self) -> Self {
77        match self {
78            Self::Positive => Self::Negative,
79            Self::Negative => Self::Positive,
80        }
81    }
82}
83
84impl Mul for Sign {
85    type Output = Self;
86    fn mul(self, rhs: Self) -> Self {
87        match self {
88            Self::Positive => rhs,
89            Self::Negative => -rhs,
90        }
91    }
92}
93
94impl MulAssign for Sign {
95    fn mul_assign(&mut self, rhs: Self) {
96        *self = *self * rhs;
97    }
98}
99
100/// type of underlying bits used to implement Float
101pub trait FloatBitsType:
102    Unsigned
103    + Integer
104    + Clone
105    + NumAssign
106    + NumAssignRef
107    + NumRef
108    + Shl<usize, Output = Self>
109    + Shr<usize, Output = Self>
110    + ShlAssign<usize>
111    + ShrAssign<usize>
112    + BitAnd<Self, Output = Self>
113    + BitOr<Self, Output = Self>
114    + BitXor<Self, Output = Self>
115    + for<'a> BitAnd<&'a Self, Output = Self>
116    + for<'a> BitOr<&'a Self, Output = Self>
117    + for<'a> BitXor<&'a Self, Output = Self>
118    + BitAndAssign<Self>
119    + BitOrAssign<Self>
120    + BitXorAssign<Self>
121    + for<'a> BitAndAssign<&'a Self>
122    + for<'a> BitOrAssign<&'a Self>
123    + for<'a> BitXorAssign<&'a Self>
124    + fmt::UpperHex
125    + fmt::LowerHex
126    + fmt::Octal
127    + fmt::Binary
128    + fmt::Display
129    + FromPrimitive
130    + ToPrimitive
131    + Into<BigInt>
132    + From<u8>
133{
134    /// convert `v` to `Self`, returning `Some` if the value fits,
135    /// otherwise returning `None`.
136    fn from_bigint(v: &BigInt) -> Option<Self>;
137}
138
139macro_rules! impl_float_bits_type {
140    ($t:ty, $cvt_from_bigint:ident) => {
141        impl FloatBitsType for $t {
142            fn from_bigint(v: &BigInt) -> Option<Self> {
143                v.$cvt_from_bigint()
144            }
145        }
146    };
147}
148
149impl_float_bits_type!(BigUint, to_biguint);
150impl_float_bits_type!(u8, to_u8);
151impl_float_bits_type!(u16, to_u16);
152impl_float_bits_type!(u32, to_u32);
153impl_float_bits_type!(u64, to_u64);
154impl_float_bits_type!(u128, to_u128);
155
156python_enum! {
157    #[pyenum(module = simple_soft_float, repr = u8, test_fn = test_rounding_mode_enum)]
158    /// floating-point rounding mode
159    pub enum RoundingMode {
160        /// round to nearest, ties to even
161        TiesToEven = 0,
162        /// round toward zero
163        TowardZero = 1,
164        /// round toward negative infinity
165        TowardNegative = 2,
166        /// round toward positive infinity
167        TowardPositive = 3,
168        /// round to nearest, ties away from zero
169        TiesToAway = 4,
170    }
171}
172
173impl Default for RoundingMode {
174    fn default() -> Self {
175        RoundingMode::TiesToEven
176    }
177}
178
179bitflags! {
180    /// IEEE 754 status flags
181    pub struct StatusFlags: u32 {
182        /// Signaled if there is no usefully definable result.
183        const INVALID_OPERATION = 0b00001;
184        /// Signaled when a exact infinite result is generated from an operation
185        /// on finite operands.
186        const DIVISION_BY_ZERO = 0b00010;
187        /// Signaled when what would be the correctly rounded result were the
188        /// exponent range unbounded is larger in magnitude than the largest
189        /// finite representable number.
190        const OVERFLOW = 0b00100;
191        /// Signaled when a tiny non-zero result is detected.
192        const UNDERFLOW = 0b01000;
193        /// Signaled when the result of a floating-point operation is not exact.
194        const INEXACT = 0b10000;
195    }
196}
197
198impl Default for StatusFlags {
199    fn default() -> Self {
200        StatusFlags::empty()
201    }
202}
203
204python_enum! {
205    #[pyenum(module = simple_soft_float, repr = u8, test_fn = test_exception_handling_mode_enum)]
206    /// Select if the underflow exception should be signaled when the result is exact.
207    ///
208    /// In IEEE 754, when exceptions are set to use the default handlers
209    /// (they are ignored -- the default for most programming languages), then
210    /// underflow exceptions are only signalled when the result is not exact.
211    ///
212    /// When exceptions are instead set to trap, then underflow exceptions are
213    /// signalled even when the result is exact, to allow the exception handler
214    /// to emulate flush-to-zero FP semantics.
215    ///
216    /// Since simple-soft-float doesn't support trapping exceptions, to simulate
217    /// trapping exceptions, use `SignalExactUnderflow` as the exception
218    /// handling mode and check `status_flags` after every operation.
219    ///
220    /// Otherwise, use the default value of `IgnoreExactUnderflow`.
221    pub enum ExceptionHandlingMode {
222        /// Use the default behavior of ignoring exact underflow.
223        IgnoreExactUnderflow,
224        /// Signal the `UNDERFLOW` exception even if the results are exact.
225        SignalExactUnderflow,
226    }
227}
228
229impl Default for ExceptionHandlingMode {
230    fn default() -> ExceptionHandlingMode {
231        ExceptionHandlingMode::IgnoreExactUnderflow
232    }
233}
234
235python_enum! {
236    #[pyenum(module = simple_soft_float, repr = u8, test_fn = test_tininess_detection_mode_enum)]
237    /// IEEE 754 tininess detection mode
238    pub enum TininessDetectionMode {
239        /// tininess is detected after rounding
240        AfterRounding,
241        /// tininess is detected before rounding
242        BeforeRounding,
243    }
244}
245
246impl Default for TininessDetectionMode {
247    fn default() -> TininessDetectionMode {
248        TininessDetectionMode::AfterRounding
249    }
250}
251
252python_enum! {
253    #[pyenum(module = simple_soft_float, repr = u8, test_fn = test_binary_nan_propagation_mode_enum)]
254    /// Select how NaN payloads should be propagated
255    pub enum BinaryNaNPropagationMode {
256        /// NaN payloads are always canonical
257        AlwaysCanonical,
258        /// If the first argument is a NaN, then the result uses the first argument's payload,
259        /// else if the second argument is a NaN, then the result uses the second argument's payload,
260        /// else the result is the canonical NaN.
261        FirstSecond,
262        /// If the second argument is a NaN, then the result uses the second argument's payload,
263        /// else if the first argument is a NaN, then the result uses the first argument's payload,
264        /// else the result is the canonical NaN.
265        SecondFirst,
266        /// If the first argument is a signaling NaN, then the result uses the first argument's payload,
267        /// else if the second argument is a signaling NaN, then the result uses the second argument's payload,
268        /// else if the first argument is a NaN, then the result uses the first argument's payload,
269        /// else if the second argument is a NaN, then the result uses the second argument's payload,
270        /// else the result is the canonical NaN.
271        FirstSecondPreferringSNaN,
272        /// If the second argument is a signaling NaN, then the result uses the second argument's payload,
273        /// else if the first argument is a signaling NaN, then the result uses the first argument's payload,
274        /// else if the second argument is a NaN, then the result uses the second argument's payload,
275        /// else if the first argument is a NaN, then the result uses the first argument's payload,
276        /// else the result is the canonical NaN.
277        SecondFirstPreferringSNaN,
278    }
279}
280
281python_enum! {
282    #[pyenum(module = simple_soft_float, repr = u8, test_fn = test_unary_nan_propagation_mode_enum)]
283    /// Select how NaN payloads should be propagated
284    pub enum UnaryNaNPropagationMode {
285        /// NaN payloads are always canonical
286        AlwaysCanonical,
287        /// If the first argument is a NaN, then the result uses the first argument's payload,
288        /// else the result is the canonical NaN.
289        First,
290    }
291}
292
293/// results of NaN propagation for binary operation
294#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
295pub enum BinaryNaNPropagationResults {
296    /// NaN should be canonical
297    Canonical,
298    /// Take NaN payload from first argument
299    First,
300    /// Take NaN payload from second argument
301    Second,
302}
303
304impl Default for BinaryNaNPropagationResults {
305    fn default() -> Self {
306        Self::Canonical
307    }
308}
309
310impl BinaryNaNPropagationMode {
311    /// calculate the result of NaN propagation for a floating-point operation
312    pub fn calculate_propagation_results(
313        self,
314        first_class: FloatClass,
315        second_class: FloatClass,
316    ) -> BinaryNaNPropagationResults {
317        use BinaryNaNPropagationMode::*;
318        use BinaryNaNPropagationResults::*;
319        match self {
320            AlwaysCanonical => Canonical,
321            FirstSecond => {
322                if first_class.is_nan() {
323                    First
324                } else if second_class.is_nan() {
325                    Second
326                } else {
327                    Canonical
328                }
329            }
330            SecondFirst => {
331                if second_class.is_nan() {
332                    Second
333                } else if first_class.is_nan() {
334                    First
335                } else {
336                    Canonical
337                }
338            }
339            FirstSecondPreferringSNaN => {
340                if first_class.is_signaling_nan() {
341                    First
342                } else if second_class.is_signaling_nan() {
343                    Second
344                } else if first_class.is_nan() {
345                    First
346                } else if second_class.is_nan() {
347                    Second
348                } else {
349                    Canonical
350                }
351            }
352            SecondFirstPreferringSNaN => {
353                if second_class.is_signaling_nan() {
354                    Second
355                } else if first_class.is_signaling_nan() {
356                    First
357                } else if second_class.is_nan() {
358                    Second
359                } else if first_class.is_nan() {
360                    First
361                } else {
362                    Canonical
363                }
364            }
365        }
366    }
367}
368
369/// results of NaN propagation for unary operation
370#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
371pub enum UnaryNaNPropagationResults {
372    /// NaN should be canonical
373    Canonical,
374    /// Take NaN payload from first argument
375    First,
376}
377
378impl Default for UnaryNaNPropagationResults {
379    fn default() -> Self {
380        Self::Canonical
381    }
382}
383
384impl UnaryNaNPropagationMode {
385    /// calculate the result of NaN propagation for a floating-point operation
386    pub fn calculate_propagation_results(
387        self,
388        first_class: FloatClass,
389    ) -> UnaryNaNPropagationResults {
390        match self {
391            UnaryNaNPropagationMode::AlwaysCanonical => UnaryNaNPropagationResults::Canonical,
392            UnaryNaNPropagationMode::First => {
393                if first_class.is_nan() {
394                    UnaryNaNPropagationResults::First
395                } else {
396                    UnaryNaNPropagationResults::Canonical
397                }
398            }
399        }
400    }
401}
402
403impl From<TernaryNaNPropagationMode> for BinaryNaNPropagationMode {
404    fn from(v: TernaryNaNPropagationMode) -> Self {
405        use BinaryNaNPropagationMode::*;
406        use TernaryNaNPropagationMode::*;
407        match v {
408            TernaryNaNPropagationMode::AlwaysCanonical => BinaryNaNPropagationMode::AlwaysCanonical,
409            FirstSecondThird | FirstThirdSecond | ThirdFirstSecond => FirstSecond,
410            SecondFirstThird | SecondThirdFirst | ThirdSecondFirst => SecondFirst,
411            FirstSecondThirdPreferringSNaN
412            | FirstThirdSecondPreferringSNaN
413            | ThirdFirstSecondPreferringSNaN => FirstSecondPreferringSNaN,
414            SecondFirstThirdPreferringSNaN
415            | SecondThirdFirstPreferringSNaN
416            | ThirdSecondFirstPreferringSNaN => SecondFirstPreferringSNaN,
417        }
418    }
419}
420
421impl From<BinaryNaNPropagationMode> for UnaryNaNPropagationMode {
422    fn from(v: BinaryNaNPropagationMode) -> Self {
423        use BinaryNaNPropagationMode::*;
424        use UnaryNaNPropagationMode::*;
425        match v {
426            BinaryNaNPropagationMode::AlwaysCanonical => UnaryNaNPropagationMode::AlwaysCanonical,
427            FirstSecond | SecondFirst | FirstSecondPreferringSNaN | SecondFirstPreferringSNaN => {
428                First
429            }
430        }
431    }
432}
433
434/// results of NaN propagation for ternary operation
435#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
436pub enum TernaryNaNPropagationResults {
437    /// NaN should be canonical
438    Canonical,
439    /// Take NaN payload from first argument
440    First,
441    /// Take NaN payload from second argument
442    Second,
443    /// Take NaN payload from third argument
444    Third,
445}
446
447impl Default for TernaryNaNPropagationResults {
448    fn default() -> Self {
449        Self::Canonical
450    }
451}
452
453python_enum! {
454    #[pyenum(module = simple_soft_float, repr = u8, test_fn = test_ternary_nan_propagation_mode_enum)]
455    /// Select how NaN payloads should be propagated
456    pub enum TernaryNaNPropagationMode {
457        /// NaN payloads are always canonical
458        AlwaysCanonical,
459        /// If the first argument is a NaN, then the result uses the first argument's payload,
460        /// else if the second argument is a NaN, then the result uses the second argument's payload,
461        /// else if the third argument is a NaN, then the result uses the third argument's payload,
462        /// else the result is the canonical NaN.
463        FirstSecondThird,
464        /// If the first argument is a NaN, then the result uses the first argument's payload,
465        /// else if the third argument is a NaN, then the result uses the third argument's payload,
466        /// else if the second argument is a NaN, then the result uses the second argument's payload,
467        /// else the result is the canonical NaN.
468        FirstThirdSecond,
469        /// If the second argument is a NaN, then the result uses the second argument's payload,
470        /// else if the first argument is a NaN, then the result uses the first argument's payload,
471        /// else if the third argument is a NaN, then the result uses the third argument's payload,
472        /// else the result is the canonical NaN.
473        SecondFirstThird,
474        /// If the second argument is a NaN, then the result uses the second argument's payload,
475        /// else if the third argument is a NaN, then the result uses the third argument's payload,
476        /// else if the first argument is a NaN, then the result uses the first argument's payload,
477        /// else the result is the canonical NaN.
478        SecondThirdFirst,
479        /// If the third argument is a NaN, then the result uses the third argument's payload,
480        /// else if the first argument is a NaN, then the result uses the first argument's payload,
481        /// else if the second argument is a NaN, then the result uses the second argument's payload,
482        /// else the result is the canonical NaN.
483        ThirdFirstSecond,
484        /// If the third argument is a NaN, then the result uses the third argument's payload,
485        /// else if the second argument is a NaN, then the result uses the second argument's payload,
486        /// else if the first argument is a NaN, then the result uses the first argument's payload,
487        /// else the result is the canonical NaN.
488        ThirdSecondFirst,
489        /// If the first argument is a signaling NaN, then the result uses the first argument's payload,
490        /// else if the second argument is a signaling NaN, then the result uses the second argument's payload,
491        /// else if the third argument is a signaling NaN, then the result uses the third argument's payload,
492        /// else if the first argument is a NaN, then the result uses the first argument's payload,
493        /// else if the second argument is a NaN, then the result uses the second argument's payload,
494        /// else if the third argument is a NaN, then the result uses the third argument's payload,
495        /// else the result is the canonical NaN.
496        FirstSecondThirdPreferringSNaN,
497        /// If the first argument is a signaling NaN, then the result uses the first argument's payload,
498        /// else if the third argument is a signaling NaN, then the result uses the third argument's payload,
499        /// else if the second argument is a signaling NaN, then the result uses the second argument's payload,
500        /// else if the first argument is a NaN, then the result uses the first argument's payload,
501        /// else if the third argument is a NaN, then the result uses the third argument's payload,
502        /// else if the second argument is a NaN, then the result uses the second argument's payload,
503        /// else the result is the canonical NaN.
504        FirstThirdSecondPreferringSNaN,
505        /// If the second argument is a signaling NaN, then the result uses the second argument's payload,
506        /// else if the first argument is a signaling NaN, then the result uses the first argument's payload,
507        /// else if the third argument is a signaling NaN, then the result uses the third argument's payload,
508        /// else if the second argument is a NaN, then the result uses the second argument's payload,
509        /// else if the first argument is a NaN, then the result uses the first argument's payload,
510        /// else if the third argument is a NaN, then the result uses the third argument's payload,
511        /// else the result is the canonical NaN.
512        SecondFirstThirdPreferringSNaN,
513        /// If the second argument is a signaling NaN, then the result uses the second argument's payload,
514        /// else if the third argument is a signaling NaN, then the result uses the third argument's payload,
515        /// else if the first argument is a signaling NaN, then the result uses the first argument's payload,
516        /// else if the second argument is a NaN, then the result uses the second argument's payload,
517        /// else if the third argument is a NaN, then the result uses the third argument's payload,
518        /// else if the first argument is a NaN, then the result uses the first argument's payload,
519        /// else the result is the canonical NaN.
520        SecondThirdFirstPreferringSNaN,
521        /// If the third argument is a signaling NaN, then the result uses the third argument's payload,
522        /// else if the first argument is a signaling NaN, then the result uses the first argument's payload,
523        /// else if the second argument is a signaling NaN, then the result uses the second argument's payload,
524        /// else if the third argument is a NaN, then the result uses the third argument's payload,
525        /// else if the first argument is a NaN, then the result uses the first argument's payload,
526        /// else if the second argument is a NaN, then the result uses the second argument's payload,
527        /// else the result is the canonical NaN.
528        ThirdFirstSecondPreferringSNaN,
529        /// If the third argument is a signaling NaN, then the result uses the third argument's payload,
530        /// else if the second argument is a signaling NaN, then the result uses the second argument's payload,
531        /// else if the first argument is a signaling NaN, then the result uses the first argument's payload,
532        /// else if the third argument is a NaN, then the result uses the third argument's payload,
533        /// else if the second argument is a NaN, then the result uses the second argument's payload,
534        /// else if the first argument is a NaN, then the result uses the first argument's payload,
535        /// else the result is the canonical NaN.
536        ThirdSecondFirstPreferringSNaN,
537    }
538}
539
540impl Default for TernaryNaNPropagationMode {
541    fn default() -> TernaryNaNPropagationMode {
542        TernaryNaNPropagationMode::AlwaysCanonical
543    }
544}
545
546impl TernaryNaNPropagationMode {
547    /// calculate the result of NaN propagation for a floating-point operation
548    pub fn calculate_propagation_results(
549        self,
550        first_class: FloatClass,
551        second_class: FloatClass,
552        third_class: FloatClass,
553    ) -> TernaryNaNPropagationResults {
554        #![allow(clippy::cognitive_complexity)]
555        use TernaryNaNPropagationMode::*;
556        use TernaryNaNPropagationResults::*;
557        match self {
558            AlwaysCanonical => Canonical,
559            FirstSecondThird => {
560                if first_class.is_nan() {
561                    First
562                } else if second_class.is_nan() {
563                    Second
564                } else if third_class.is_nan() {
565                    Third
566                } else {
567                    Canonical
568                }
569            }
570            FirstSecondThirdPreferringSNaN => {
571                if first_class.is_signaling_nan() {
572                    First
573                } else if second_class.is_signaling_nan() {
574                    Second
575                } else if third_class.is_signaling_nan() {
576                    Third
577                } else if first_class.is_nan() {
578                    First
579                } else if second_class.is_nan() {
580                    Second
581                } else if third_class.is_nan() {
582                    Third
583                } else {
584                    Canonical
585                }
586            }
587            FirstThirdSecond => {
588                if first_class.is_nan() {
589                    First
590                } else if third_class.is_nan() {
591                    Third
592                } else if second_class.is_nan() {
593                    Second
594                } else {
595                    Canonical
596                }
597            }
598            FirstThirdSecondPreferringSNaN => {
599                if first_class.is_signaling_nan() {
600                    First
601                } else if third_class.is_signaling_nan() {
602                    Third
603                } else if second_class.is_signaling_nan() {
604                    Second
605                } else if first_class.is_nan() {
606                    First
607                } else if third_class.is_nan() {
608                    Third
609                } else if second_class.is_nan() {
610                    Second
611                } else {
612                    Canonical
613                }
614            }
615            SecondFirstThird => {
616                if second_class.is_nan() {
617                    Second
618                } else if first_class.is_nan() {
619                    First
620                } else if third_class.is_nan() {
621                    Third
622                } else {
623                    Canonical
624                }
625            }
626            SecondFirstThirdPreferringSNaN => {
627                if second_class.is_signaling_nan() {
628                    Second
629                } else if first_class.is_signaling_nan() {
630                    First
631                } else if third_class.is_signaling_nan() {
632                    Third
633                } else if second_class.is_nan() {
634                    Second
635                } else if first_class.is_nan() {
636                    First
637                } else if third_class.is_nan() {
638                    Third
639                } else {
640                    Canonical
641                }
642            }
643            SecondThirdFirst => {
644                if second_class.is_nan() {
645                    Second
646                } else if third_class.is_nan() {
647                    Third
648                } else if first_class.is_nan() {
649                    First
650                } else {
651                    Canonical
652                }
653            }
654            SecondThirdFirstPreferringSNaN => {
655                if second_class.is_signaling_nan() {
656                    Second
657                } else if third_class.is_signaling_nan() {
658                    Third
659                } else if first_class.is_signaling_nan() {
660                    First
661                } else if second_class.is_nan() {
662                    Second
663                } else if third_class.is_nan() {
664                    Third
665                } else if first_class.is_nan() {
666                    First
667                } else {
668                    Canonical
669                }
670            }
671            ThirdFirstSecond => {
672                if third_class.is_nan() {
673                    Third
674                } else if first_class.is_nan() {
675                    First
676                } else if second_class.is_nan() {
677                    Second
678                } else {
679                    Canonical
680                }
681            }
682            ThirdFirstSecondPreferringSNaN => {
683                if third_class.is_signaling_nan() {
684                    Third
685                } else if first_class.is_signaling_nan() {
686                    First
687                } else if second_class.is_signaling_nan() {
688                    Second
689                } else if third_class.is_nan() {
690                    Third
691                } else if first_class.is_nan() {
692                    First
693                } else if second_class.is_nan() {
694                    Second
695                } else {
696                    Canonical
697                }
698            }
699            ThirdSecondFirst => {
700                if third_class.is_nan() {
701                    Third
702                } else if second_class.is_nan() {
703                    Second
704                } else if first_class.is_nan() {
705                    First
706                } else {
707                    Canonical
708                }
709            }
710            ThirdSecondFirstPreferringSNaN => {
711                if third_class.is_signaling_nan() {
712                    Third
713                } else if second_class.is_signaling_nan() {
714                    Second
715                } else if first_class.is_signaling_nan() {
716                    First
717                } else if third_class.is_nan() {
718                    Third
719                } else if second_class.is_nan() {
720                    Second
721                } else if first_class.is_nan() {
722                    First
723                } else {
724                    Canonical
725                }
726            }
727        }
728    }
729}
730
731python_enum! {
732    #[pyenum(module = simple_soft_float, repr = u8, test_fn = test_fma_inf_zero_qnan_result_enum)]
733    /// select the result of fused `Infinity * 0.0 + QNaN` and `0.0 * Infinity + QNaN`
734    pub enum FMAInfZeroQNaNResult {
735        /// follow the NaN propagation mode without signaling the `INVALID_OPERATION` exception
736        FollowNaNPropagationMode,
737        /// generate a canonical NaN and signal the `INVALID_OPERATION` exception
738        CanonicalAndGenerateInvalid,
739        /// follow the NaN propagation mode and signal the `INVALID_OPERATION` exception
740        PropagateAndGenerateInvalid,
741    }
742}
743
744impl Default for FMAInfZeroQNaNResult {
745    fn default() -> FMAInfZeroQNaNResult {
746        FMAInfZeroQNaNResult::FollowNaNPropagationMode
747    }
748}
749
750python_enum! {
751    #[pyenum(module = simple_soft_float, repr = u8, test_fn = test_float_to_float_conversion_nan_propagation_mode_enum)]
752    /// select how NaN payloads are propagated in float -> float conversions
753    pub enum FloatToFloatConversionNaNPropagationMode {
754        /// NaN payloads are always canonical
755        AlwaysCanonical,
756        /// NaN payloads are copied, zero-extending or truncating as many bits as
757        /// necessary from the LSB side of the payload, retaining the most-significant bits.
758        RetainMostSignificantBits,
759    }
760}
761
762/// The dynamic state of a floating-point implementation
763#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
764pub struct FPState {
765    /// the dynamic rounding mode -- used whenever the rounding mode is not explicitly overridden
766    pub rounding_mode: RoundingMode,
767    /// the cumulative exception status flags
768    pub status_flags: StatusFlags,
769    /// the exception handling mode
770    pub exception_handling_mode: ExceptionHandlingMode,
771    /// the tininess detection mode
772    pub tininess_detection_mode: TininessDetectionMode,
773    // FIXME: switch to using #[non_exhaustive] once on stable (rustc 1.40)
774    _non_exhaustive: (),
775}
776
777/// `FPState` merging failed due to incompatibility
778#[derive(Clone, Debug, Default)]
779pub struct FPStateMergeFailed;
780
781impl fmt::Display for FPStateMergeFailed {
782    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
783        f.write_str("FPState::merge failed: incompatible states")
784    }
785}
786
787impl Error for FPStateMergeFailed {}
788
789#[cfg(feature = "python")]
790impl From<FPStateMergeFailed> for PyErr {
791    fn from(value: FPStateMergeFailed) -> PyErr {
792        PyErr::new::<pyo3::exceptions::TypeError, _>(format!("{}", value))
793    }
794}
795
796impl FPState {
797    /// combine two `FPState` values into one, assigning the result to `self`
798    pub fn checked_merge_assign(&mut self, rhs: Self) -> Result<(), FPStateMergeFailed> {
799        let status_flags = self.status_flags | rhs.status_flags;
800        let same = Self {
801            status_flags,
802            ..*self
803        } == Self {
804            status_flags,
805            ..rhs
806        };
807        if same {
808            self.status_flags = status_flags;
809            Ok(())
810        } else {
811            Err(FPStateMergeFailed)
812        }
813    }
814    /// combine two `FPState` values into one, assigning the result to `self`
815    pub fn merge_assign(&mut self, rhs: Self) {
816        self.checked_merge_assign(rhs).unwrap();
817    }
818    /// combine two `FPState` values into one, returning the result
819    pub fn checked_merge(mut self, rhs: Self) -> Result<Self, FPStateMergeFailed> {
820        self.checked_merge_assign(rhs)?;
821        Ok(self)
822    }
823    /// combine two `FPState` values into one, returning the result
824    pub fn merge(mut self, rhs: Self) -> Self {
825        self.merge_assign(rhs);
826        self
827    }
828}
829
830python_enum! {
831    #[pyenum(module = simple_soft_float, repr = u8, test_fn = test_float_class_enum)]
832    /// float classification
833    pub enum FloatClass {
834        /// negative infinity
835        NegativeInfinity,
836        /// negative normal
837        NegativeNormal,
838        /// negative subnormal
839        NegativeSubnormal,
840        /// negative zero
841        NegativeZero,
842        /// positive infinity
843        PositiveInfinity,
844        /// positive normal
845        PositiveNormal,
846        /// positive subnormal
847        PositiveSubnormal,
848        /// positive zero
849        PositiveZero,
850        /// quiet NaN
851        QuietNaN,
852        /// signaling NaN
853        SignalingNaN,
854    }
855}
856
857impl FloatClass {
858    /// get sign of non-NaN values
859    #[inline]
860    pub fn sign(self) -> Option<Sign> {
861        match self {
862            FloatClass::NegativeInfinity
863            | FloatClass::NegativeNormal
864            | FloatClass::NegativeSubnormal
865            | FloatClass::NegativeZero => Some(Sign::Negative),
866            FloatClass::PositiveInfinity
867            | FloatClass::PositiveNormal
868            | FloatClass::PositiveSubnormal
869            | FloatClass::PositiveZero => Some(Sign::Positive),
870            FloatClass::QuietNaN | FloatClass::SignalingNaN => None,
871        }
872    }
873    /// convert negative to positive
874    #[inline]
875    pub fn abs(self) -> Self {
876        match self {
877            FloatClass::NegativeInfinity => FloatClass::PositiveInfinity,
878            FloatClass::NegativeNormal => FloatClass::PositiveNormal,
879            FloatClass::NegativeSubnormal => FloatClass::PositiveSubnormal,
880            FloatClass::NegativeZero => FloatClass::PositiveZero,
881            FloatClass::PositiveInfinity => FloatClass::PositiveInfinity,
882            FloatClass::PositiveNormal => FloatClass::PositiveNormal,
883            FloatClass::PositiveSubnormal => FloatClass::PositiveSubnormal,
884            FloatClass::PositiveZero => FloatClass::PositiveZero,
885            FloatClass::QuietNaN => FloatClass::QuietNaN,
886            FloatClass::SignalingNaN => FloatClass::SignalingNaN,
887        }
888    }
889    /// return `true` if `self` is `NegativeInfinity`
890    #[inline]
891    pub fn is_negative_infinity(self) -> bool {
892        self == FloatClass::NegativeInfinity
893    }
894    /// return `true` if `self` is `NegativeNormal`
895    #[inline]
896    pub fn is_negative_normal(self) -> bool {
897        self == FloatClass::NegativeNormal
898    }
899    /// return `true` if `self` is `NegativeSubnormal`
900    #[inline]
901    pub fn is_negative_subnormal(self) -> bool {
902        self == FloatClass::NegativeSubnormal
903    }
904    /// return `true` if `self` is `NegativeZero`
905    #[inline]
906    pub fn is_negative_zero(self) -> bool {
907        self == FloatClass::NegativeZero
908    }
909    /// return `true` if `self` is `PositiveInfinity`
910    #[inline]
911    pub fn is_positive_infinity(self) -> bool {
912        self == FloatClass::PositiveInfinity
913    }
914    /// return `true` if `self` is `PositiveNormal`
915    #[inline]
916    pub fn is_positive_normal(self) -> bool {
917        self == FloatClass::PositiveNormal
918    }
919    /// return `true` if `self` is `PositiveSubnormal`
920    #[inline]
921    pub fn is_positive_subnormal(self) -> bool {
922        self == FloatClass::PositiveSubnormal
923    }
924    /// return `true` if `self` is `PositiveZero`
925    #[inline]
926    pub fn is_positive_zero(self) -> bool {
927        self == FloatClass::PositiveZero
928    }
929    /// return `true` if `self` is `QuietNaN`
930    #[inline]
931    pub fn is_quiet_nan(self) -> bool {
932        self == FloatClass::QuietNaN
933    }
934    /// return `true` if `self` is `SignalingNaN`
935    #[inline]
936    pub fn is_signaling_nan(self) -> bool {
937        self == FloatClass::SignalingNaN
938    }
939    /// return `true` if `self` is infinity
940    #[inline]
941    pub fn is_infinity(self) -> bool {
942        self == FloatClass::NegativeInfinity || self == FloatClass::PositiveInfinity
943    }
944    /// return `true` if `self` is `NegativeNormal` or `PositiveNormal`
945    #[inline]
946    pub fn is_normal(self) -> bool {
947        self == FloatClass::NegativeNormal || self == FloatClass::PositiveNormal
948    }
949    /// return `true` if `self` is subnormal
950    #[inline]
951    pub fn is_subnormal(self) -> bool {
952        self == FloatClass::NegativeSubnormal || self == FloatClass::PositiveSubnormal
953    }
954    /// return `true` if `self` is zero
955    #[inline]
956    pub fn is_zero(self) -> bool {
957        self == FloatClass::NegativeZero || self == FloatClass::PositiveZero
958    }
959    /// return `true` if `self` is NaN
960    #[inline]
961    pub fn is_nan(self) -> bool {
962        self == FloatClass::QuietNaN || self == FloatClass::SignalingNaN
963    }
964    /// return `true` if `self` is finite (not NaN or infinity)
965    #[inline]
966    pub fn is_finite(self) -> bool {
967        match self {
968            FloatClass::NegativeZero
969            | FloatClass::NegativeSubnormal
970            | FloatClass::NegativeNormal
971            | FloatClass::PositiveZero
972            | FloatClass::PositiveSubnormal
973            | FloatClass::PositiveNormal => true,
974            _ => false,
975        }
976    }
977    /// return `true` if `self` is subnormal or zero
978    #[inline]
979    pub fn is_subnormal_or_zero(self) -> bool {
980        match self {
981            FloatClass::NegativeZero
982            | FloatClass::NegativeSubnormal
983            | FloatClass::PositiveZero
984            | FloatClass::PositiveSubnormal => true,
985            _ => false,
986        }
987    }
988}
989
990impl Neg for FloatClass {
991    type Output = Self;
992    fn neg(self) -> Self {
993        use FloatClass::*;
994        match self {
995            NegativeInfinity => PositiveInfinity,
996            NegativeNormal => PositiveNormal,
997            NegativeSubnormal => PositiveSubnormal,
998            NegativeZero => PositiveZero,
999            PositiveInfinity => NegativeInfinity,
1000            PositiveNormal => NegativeNormal,
1001            PositiveSubnormal => NegativeSubnormal,
1002            PositiveZero => NegativeZero,
1003            QuietNaN => QuietNaN,
1004            SignalingNaN => SignalingNaN,
1005        }
1006    }
1007}
1008
1009python_enum! {
1010    #[pyenum(module = simple_soft_float, repr = u8, test_fn = test_quiet_nan_format_enum)]
1011    /// the format for quiet NaN values
1012    ///
1013    /// IEEE 754 states that implementations *should* use the MSB of the
1014    /// mantissa being set to indicate a quiet NaN, however MIPS before
1015    /// the 2008 revision and PA-RISC use the MSB of the mantissa being clear
1016    /// to indicate a quiet NaN.
1017    pub enum QuietNaNFormat {
1018        /// MSB of mantissa set to indicate quiet NaN
1019        Standard,
1020        /// MSB of mantissa clear to indicate quiet NaN; also used in PA-RISC
1021        MIPSLegacy,
1022    }
1023}
1024
1025impl QuietNaNFormat {
1026    /// returns `true` if a NaN with the mantissa MSB set to `mantissa_msb_set` is a quiet NaN
1027    pub fn is_nan_quiet(self, mantissa_msb_set: bool) -> bool {
1028        match self {
1029            QuietNaNFormat::Standard => mantissa_msb_set,
1030            QuietNaNFormat::MIPSLegacy => !mantissa_msb_set,
1031        }
1032    }
1033}
1034
1035impl Default for QuietNaNFormat {
1036    fn default() -> QuietNaNFormat {
1037        QuietNaNFormat::Standard
1038    }
1039}
1040
1041/// properties of a floating-point implementation
1042#[derive(Copy, Clone, Eq, PartialEq, Hash)]
1043pub struct PlatformProperties {
1044    /// sign of the canonical NaN
1045    pub canonical_nan_sign: Sign,
1046    /// most-significant-bit of the mantissa of the canonical NaN
1047    pub canonical_nan_mantissa_msb: bool,
1048    /// second-most-significant-bit of the mantissa of the canonical NaN
1049    pub canonical_nan_mantissa_second_to_msb: bool,
1050    /// rest of the bits of the mantissa of the canonical NaN
1051    pub canonical_nan_mantissa_rest: bool,
1052    /// NaN payload propagation mode for the standard binary operations
1053    pub std_bin_ops_nan_propagation_mode: BinaryNaNPropagationMode,
1054    /// NaN payload propagation mode for `fused_mul_add`
1055    pub fma_nan_propagation_mode: TernaryNaNPropagationMode,
1056    /// the result of `fused_mul_add` for `(Infinity * 0.0) + QNaN` and
1057    /// `(0.0 * Infinity) + QNaN`
1058    pub fma_inf_zero_qnan_result: FMAInfZeroQNaNResult,
1059    /// NaN payload propagation mode for `round_to_integral`
1060    pub round_to_integral_nan_propagation_mode: UnaryNaNPropagationMode,
1061    /// NaN payload propagation mode for `next_up_or_down`, `next_up`, and `next_down`
1062    pub next_up_or_down_nan_propagation_mode: UnaryNaNPropagationMode,
1063    /// NaN payload propagation mode for `scale_b`
1064    pub scale_b_nan_propagation_mode: UnaryNaNPropagationMode,
1065    /// NaN payload propagation mode for `sqrt`
1066    pub sqrt_nan_propagation_mode: UnaryNaNPropagationMode,
1067    /// NaN payload propagation mode for float-to-float conversions
1068    pub float_to_float_conversion_nan_propagation_mode: FloatToFloatConversionNaNPropagationMode,
1069    /// NaN payload propagation mode for `rsqrt`
1070    pub rsqrt_nan_propagation_mode: UnaryNaNPropagationMode,
1071    // FIXME: switch to using #[non_exhaustive] once on stable (rustc 1.40)
1072    _non_exhaustive: (),
1073}
1074
1075impl Default for PlatformProperties {
1076    fn default() -> PlatformProperties {
1077        PlatformProperties::default()
1078    }
1079}
1080
1081impl PlatformProperties {
1082    fn fallback_debug(&self, f: &mut fmt::Formatter) -> fmt::Result {
1083        macro_rules! platform_properties_debug_full {
1084            (let f = $f:expr; $($var_assignments:tt)+) => {
1085                {
1086                    $($var_assignments)+
1087                    platform_properties_debug_full!(@fmt $f, $($var_assignments)+)
1088                }
1089            };
1090            (@fmt $f:expr, let Self { _non_exhaustive, $($field:ident,)+ } = self; $(let $fake_field:ident = $fake_field_init:expr;)+) => {
1091                $f.debug_struct("PlatformProperties")
1092                $(.field(stringify!($field), $field))+
1093                $(.field(stringify!($fake_field), &$fake_field))+
1094                .finish()
1095            };
1096        }
1097
1098        platform_properties_debug_full! {
1099            let f = f;
1100            let Self {
1101                _non_exhaustive,
1102                canonical_nan_sign,
1103                canonical_nan_mantissa_msb,
1104                canonical_nan_mantissa_second_to_msb,
1105                canonical_nan_mantissa_rest,
1106                std_bin_ops_nan_propagation_mode,
1107                fma_nan_propagation_mode,
1108                fma_inf_zero_qnan_result,
1109                round_to_integral_nan_propagation_mode,
1110                next_up_or_down_nan_propagation_mode,
1111                scale_b_nan_propagation_mode,
1112                sqrt_nan_propagation_mode,
1113                float_to_float_conversion_nan_propagation_mode,
1114                rsqrt_nan_propagation_mode,
1115            } = self;
1116            let quiet_nan_format = self.quiet_nan_format();
1117        }
1118    }
1119}
1120
1121macro_rules! platform_properties_constants {
1122    (
1123        $(
1124            $(#[$meta:meta])*
1125            pub const $ident:ident: PlatformProperties = $init:expr;
1126        )+
1127    ) => {
1128        #[cfg(feature = "python")]
1129        impl PyPlatformProperties {
1130            fn add_to_module(py: Python, m: &PyModule) -> PyResult<()> {
1131                m.add_class::<Self>()?;
1132                $(m.add::<PyObject>(concat!("PlatformProperties_", stringify!($ident)), PlatformProperties::$ident.into_py(py))?;)+
1133                Ok(())
1134            }
1135        }
1136
1137        #[cfg(feature = "python")]
1138        impl ToPythonRepr for PlatformProperties {
1139            fn to_python_repr(&self) -> Cow<str> {
1140                $(if *self == PlatformProperties::$ident {
1141                    Cow::Borrowed(concat!("PlatformProperties_", stringify!($ident)))
1142                } else)+ {
1143                    self.fallback_to_python_repr()
1144                }
1145            }
1146        }
1147
1148        impl PlatformProperties {
1149            $(
1150                $(#[$meta])*
1151                pub const $ident: PlatformProperties = $init;
1152            )+
1153        }
1154
1155        impl fmt::Debug for PlatformProperties {
1156            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1157                $(if *self == PlatformProperties::$ident {
1158                    f.write_str(concat!("PlatformProperties::", stringify!($ident)))
1159                } else)+ {
1160                    self.fallback_debug(f)
1161                }
1162            }
1163        }
1164    };
1165}
1166
1167platform_properties_constants! {
1168    /// ARM 32-bit platform properties
1169    pub const ARM: PlatformProperties = PlatformProperties::new_simple(
1170        Sign::Positive,
1171        true,
1172        false,
1173        false,
1174        // FIXME: NaN propagation not known to be correct
1175        UnaryNaNPropagationMode::First,
1176        BinaryNaNPropagationMode::FirstSecondPreferringSNaN,
1177        TernaryNaNPropagationMode::ThirdFirstSecondPreferringSNaN,
1178        FMAInfZeroQNaNResult::CanonicalAndGenerateInvalid,
1179        FloatToFloatConversionNaNPropagationMode::RetainMostSignificantBits,
1180    );
1181    /// RISC-V platform properties
1182    pub const RISC_V: PlatformProperties = PlatformProperties::new_simple(
1183        Sign::Positive,
1184        true,
1185        false,
1186        false,
1187        UnaryNaNPropagationMode::AlwaysCanonical,
1188        BinaryNaNPropagationMode::AlwaysCanonical,
1189        TernaryNaNPropagationMode::AlwaysCanonical,
1190        FMAInfZeroQNaNResult::CanonicalAndGenerateInvalid,
1191        FloatToFloatConversionNaNPropagationMode::AlwaysCanonical,
1192    );
1193    /// Power ISA platform properties
1194    pub const POWER: PlatformProperties = PlatformProperties::new_simple(
1195        Sign::Positive,
1196        true,
1197        false,
1198        false,
1199        // FIXME: NaN propagation not known to be correct
1200        UnaryNaNPropagationMode::First,
1201        BinaryNaNPropagationMode::FirstSecond,
1202        TernaryNaNPropagationMode::FirstThirdSecond,
1203        FMAInfZeroQNaNResult::PropagateAndGenerateInvalid,
1204        FloatToFloatConversionNaNPropagationMode::RetainMostSignificantBits,
1205    );
1206    /// MIPS 2008 revision platform properties
1207    pub const MIPS_2008: PlatformProperties = PlatformProperties::new_simple(
1208        Sign::Positive,
1209        true,
1210        false,
1211        false,
1212        // FIXME: NaN propagation not known to be correct
1213        UnaryNaNPropagationMode::First,
1214        BinaryNaNPropagationMode::FirstSecondPreferringSNaN,
1215        TernaryNaNPropagationMode::ThirdFirstSecondPreferringSNaN,
1216        FMAInfZeroQNaNResult::PropagateAndGenerateInvalid,
1217        FloatToFloatConversionNaNPropagationMode::RetainMostSignificantBits,
1218    );
1219    // X86_X87 is not implemented
1220    /// x86 SSE/AVX platform properties
1221    pub const X86_SSE: PlatformProperties = PlatformProperties::new_simple(
1222        Sign::Negative,
1223        true,
1224        false,
1225        false,
1226        // FIXME: NaN propagation not known to be correct
1227        UnaryNaNPropagationMode::First,
1228        BinaryNaNPropagationMode::FirstSecond,
1229        TernaryNaNPropagationMode::FirstSecondThird,
1230        FMAInfZeroQNaNResult::FollowNaNPropagationMode,
1231        FloatToFloatConversionNaNPropagationMode::RetainMostSignificantBits,
1232    );
1233    /// Sparc platform properties
1234    pub const SPARC: PlatformProperties = PlatformProperties::new_simple(
1235        Sign::Positive,
1236        true,
1237        true,
1238        true,
1239        // FIXME: NaN propagation not known to be correct
1240        UnaryNaNPropagationMode::First,
1241        BinaryNaNPropagationMode::FirstSecondPreferringSNaN,
1242        TernaryNaNPropagationMode::FirstSecondThirdPreferringSNaN,
1243        FMAInfZeroQNaNResult::FollowNaNPropagationMode,
1244        FloatToFloatConversionNaNPropagationMode::RetainMostSignificantBits,
1245    );
1246    /// HPPA platform properties
1247    pub const HPPA: PlatformProperties = PlatformProperties::new_simple(
1248        Sign::Positive,
1249        false,
1250        true,
1251        false,
1252        // FIXME: NaN propagation not known to be correct
1253        UnaryNaNPropagationMode::First,
1254        BinaryNaNPropagationMode::FirstSecondPreferringSNaN,
1255        TernaryNaNPropagationMode::FirstSecondThirdPreferringSNaN,
1256        FMAInfZeroQNaNResult::FollowNaNPropagationMode,
1257        FloatToFloatConversionNaNPropagationMode::RetainMostSignificantBits,
1258    );
1259    /// MIPS pre-2008 revision platform properties
1260    pub const MIPS_LEGACY: PlatformProperties = PlatformProperties::new_simple(
1261        Sign::Positive,
1262        false,
1263        true,
1264        true,
1265        // FIXME: NaN propagation not known to be correct
1266        UnaryNaNPropagationMode::First,
1267        BinaryNaNPropagationMode::FirstSecondPreferringSNaN,
1268        TernaryNaNPropagationMode::FirstSecondThirdPreferringSNaN,
1269        FMAInfZeroQNaNResult::CanonicalAndGenerateInvalid,
1270        FloatToFloatConversionNaNPropagationMode::RetainMostSignificantBits,
1271    );
1272}
1273
1274impl PlatformProperties {
1275    /// create `PlatformProperties`
1276    pub const fn new_simple(
1277        canonical_nan_sign: Sign,
1278        canonical_nan_mantissa_msb: bool,
1279        canonical_nan_mantissa_second_to_msb: bool,
1280        canonical_nan_mantissa_rest: bool,
1281        unary_nan_propagation_mode: UnaryNaNPropagationMode,
1282        binary_nan_propagation_mode: BinaryNaNPropagationMode,
1283        ternary_nan_propagation_mode: TernaryNaNPropagationMode,
1284        fma_inf_zero_qnan_result: FMAInfZeroQNaNResult,
1285        float_to_float_conversion_nan_propagation_mode: FloatToFloatConversionNaNPropagationMode,
1286    ) -> Self {
1287        Self {
1288            canonical_nan_sign,
1289            canonical_nan_mantissa_msb,
1290            canonical_nan_mantissa_second_to_msb,
1291            canonical_nan_mantissa_rest,
1292            std_bin_ops_nan_propagation_mode: binary_nan_propagation_mode,
1293            fma_nan_propagation_mode: ternary_nan_propagation_mode,
1294            fma_inf_zero_qnan_result,
1295            round_to_integral_nan_propagation_mode: unary_nan_propagation_mode,
1296            next_up_or_down_nan_propagation_mode: unary_nan_propagation_mode,
1297            scale_b_nan_propagation_mode: unary_nan_propagation_mode,
1298            sqrt_nan_propagation_mode: unary_nan_propagation_mode,
1299            float_to_float_conversion_nan_propagation_mode,
1300            rsqrt_nan_propagation_mode: unary_nan_propagation_mode,
1301            _non_exhaustive: (),
1302        }
1303    }
1304    /// default `PlatformProperties`.
1305    /// currently returns `RISC_V`
1306    pub const fn default() -> Self {
1307        Self::RISC_V
1308    }
1309    /// get the `QuietNaNFormat`
1310    pub fn quiet_nan_format(self) -> QuietNaNFormat {
1311        if self.canonical_nan_mantissa_msb {
1312            QuietNaNFormat::Standard
1313        } else {
1314            QuietNaNFormat::MIPSLegacy
1315        }
1316    }
1317}
1318
1319/// `FloatProperties` values incompatible: must be equal
1320#[derive(Clone, Debug, Default)]
1321pub struct FloatPropertiesIncompatible;
1322
1323impl fmt::Display for FloatPropertiesIncompatible {
1324    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1325        f.write_str("FloatProperties values incompatible: must be equal")
1326    }
1327}
1328
1329impl Error for FloatPropertiesIncompatible {}
1330
1331#[cfg(feature = "python")]
1332impl From<FloatPropertiesIncompatible> for PyErr {
1333    fn from(value: FloatPropertiesIncompatible) -> PyErr {
1334        PyErr::new::<pyo3::exceptions::TypeError, _>(format!("{}", value))
1335    }
1336}
1337
1338/// properties of a particular floating-point format
1339#[derive(Copy, Clone, Eq, PartialEq, Hash)]
1340pub struct FloatProperties {
1341    exponent_width: usize,
1342    mantissa_width: usize,
1343    has_implicit_leading_bit: bool,
1344    has_sign_bit: bool,
1345    platform_properties: PlatformProperties,
1346}
1347
1348impl FloatProperties {
1349    /// check for compatibility between two `FloatProperties` values
1350    #[inline]
1351    pub fn check_compatibility(self, other: Self) -> Result<(), FloatPropertiesIncompatible> {
1352        if self == other {
1353            Ok(())
1354        } else {
1355            Err(FloatPropertiesIncompatible)
1356        }
1357    }
1358    /// create a new `FloatProperties` value
1359    #[inline]
1360    pub const fn new_with_extended_flags(
1361        exponent_width: usize,
1362        mantissa_width: usize,
1363        has_implicit_leading_bit: bool,
1364        has_sign_bit: bool,
1365        platform_properties: PlatformProperties,
1366    ) -> Self {
1367        Self {
1368            exponent_width,
1369            mantissa_width,
1370            has_implicit_leading_bit,
1371            has_sign_bit,
1372            platform_properties,
1373        }
1374    }
1375    /// create a new `FloatProperties` value
1376    #[inline]
1377    pub const fn new(exponent_width: usize, mantissa_width: usize) -> Self {
1378        Self {
1379            exponent_width,
1380            mantissa_width,
1381            has_implicit_leading_bit: true,
1382            has_sign_bit: true,
1383            platform_properties: PlatformProperties::default(),
1384        }
1385    }
1386    /// create a new `FloatProperties` value
1387    #[inline]
1388    pub const fn new_with_platform_properties(
1389        exponent_width: usize,
1390        mantissa_width: usize,
1391        platform_properties: PlatformProperties,
1392    ) -> Self {
1393        Self {
1394            exponent_width,
1395            mantissa_width,
1396            has_implicit_leading_bit: true,
1397            has_sign_bit: true,
1398            platform_properties,
1399        }
1400    }
1401    /// `FloatProperties` for standard [__binary16__ format](https://en.wikipedia.org/wiki/Half-precision_floating-point_format)
1402    pub const STANDARD_16: Self =
1403        Self::standard_16_with_platform_properties(PlatformProperties::default());
1404    /// `FloatProperties` for standard [__binary32__ format](https://en.wikipedia.org/wiki/Single-precision_floating-point_format)
1405    pub const STANDARD_32: Self =
1406        Self::standard_32_with_platform_properties(PlatformProperties::default());
1407    /// `FloatProperties` for standard [__binary64__ format](https://en.wikipedia.org/wiki/Double-precision_floating-point_format)
1408    pub const STANDARD_64: Self =
1409        Self::standard_64_with_platform_properties(PlatformProperties::default());
1410    /// `FloatProperties` for standard [__binary128__ format](https://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format)
1411    pub const STANDARD_128: Self =
1412        Self::standard_128_with_platform_properties(PlatformProperties::default());
1413    /// `FloatProperties` for standard [__binary16__ format](https://en.wikipedia.org/wiki/Half-precision_floating-point_format)
1414    pub const fn standard_16_with_platform_properties(
1415        platform_properties: PlatformProperties,
1416    ) -> Self {
1417        Self::new_with_platform_properties(5, 10, platform_properties)
1418    }
1419    /// `FloatProperties` for standard [__binary32__ format](https://en.wikipedia.org/wiki/Single-precision_floating-point_format)
1420    pub const fn standard_32_with_platform_properties(
1421        platform_properties: PlatformProperties,
1422    ) -> Self {
1423        Self::new_with_platform_properties(8, 23, platform_properties)
1424    }
1425    /// `FloatProperties` for standard [__binary64__ format](https://en.wikipedia.org/wiki/Double-precision_floating-point_format)
1426    pub const fn standard_64_with_platform_properties(
1427        platform_properties: PlatformProperties,
1428    ) -> Self {
1429        Self::new_with_platform_properties(11, 52, platform_properties)
1430    }
1431    /// `FloatProperties` for standard [__binary128__ format](https://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format)
1432    pub const fn standard_128_with_platform_properties(
1433        platform_properties: PlatformProperties,
1434    ) -> Self {
1435        Self::new_with_platform_properties(15, 112, platform_properties)
1436    }
1437    /// construct `FloatProperties` for standard `width`-bit binary interchange format, if it exists
1438    #[inline]
1439    pub fn standard_with_platform_properties(
1440        width: usize,
1441        platform_properties: PlatformProperties,
1442    ) -> Option<Self> {
1443        match width {
1444            16 => Some(Self::new_with_platform_properties(
1445                5,
1446                10,
1447                platform_properties,
1448            )),
1449            32 => Some(Self::new_with_platform_properties(
1450                8,
1451                23,
1452                platform_properties,
1453            )),
1454            64 => Some(Self::new_with_platform_properties(
1455                11,
1456                52,
1457                platform_properties,
1458            )),
1459            128 => Some(Self::new_with_platform_properties(
1460                15,
1461                112,
1462                platform_properties,
1463            )),
1464            _ => {
1465                if width > 128 && width.is_multiple_of(&32) {
1466                    let exponent_width = ((width as f64).log2() * 4.0).round() as usize - 13;
1467                    Some(Self::new_with_platform_properties(
1468                        exponent_width,
1469                        width - exponent_width - 1,
1470                        platform_properties,
1471                    ))
1472                } else {
1473                    None
1474                }
1475            }
1476        }
1477    }
1478    /// construct `FloatProperties` for standard `width`-bit binary interchange format, if it exists
1479    #[inline]
1480    pub fn standard(width: usize) -> Option<Self> {
1481        Self::standard_with_platform_properties(width, PlatformProperties::default())
1482    }
1483    /// check if `self` is a standard binary interchange format.
1484    #[inline]
1485    pub fn is_standard(self) -> bool {
1486        Self::standard_with_platform_properties(self.width(), self.platform_properties())
1487            == Some(self)
1488    }
1489    /// the number of bits in the exponent field
1490    #[inline]
1491    pub const fn exponent_width(self) -> usize {
1492        self.exponent_width
1493    }
1494    /// the number of bits in the mantissa field (excludes any implicit leading bit)
1495    #[inline]
1496    pub const fn mantissa_width(self) -> usize {
1497        self.mantissa_width
1498    }
1499    /// if the floating-point format uses an implicit leading bit
1500    #[inline]
1501    pub const fn has_implicit_leading_bit(self) -> bool {
1502        self.has_implicit_leading_bit
1503    }
1504    /// if the floating-point format has a sign bit
1505    #[inline]
1506    pub const fn has_sign_bit(self) -> bool {
1507        self.has_sign_bit
1508    }
1509    /// get the `PlatformProperties`
1510    #[inline]
1511    pub const fn platform_properties(self) -> PlatformProperties {
1512        self.platform_properties
1513    }
1514    /// get the `QuietNaNFormat`
1515    #[inline]
1516    pub fn quiet_nan_format(self) -> QuietNaNFormat {
1517        self.platform_properties.quiet_nan_format()
1518    }
1519    /// get the floating-point format's width in bits
1520    #[inline]
1521    pub const fn width(self) -> usize {
1522        self.has_sign_bit as usize + self.exponent_width + self.mantissa_width
1523    }
1524    /// get the number of bits after the radix point in the representation of normal floating-point values
1525    #[inline]
1526    pub const fn fraction_width(self) -> usize {
1527        self.mantissa_width - !self.has_implicit_leading_bit as usize
1528    }
1529    /// get the amount by which the floating-point bits should be shifted right
1530    /// in order to extract the sign field.
1531    ///
1532    /// the sign field can be extracted using `(bits & sign_field_mask) >> sign_field_shift`
1533    #[inline]
1534    pub const fn sign_field_shift(self) -> usize {
1535        self.exponent_width + self.mantissa_width
1536    }
1537    /// get the bitwise mask for the sign field (before shifting to extract).
1538    ///
1539    /// the sign field can be extracted using `(bits & sign_field_mask) >> sign_field_shift`
1540    pub fn sign_field_mask<Bits: FloatBitsType>(self) -> Bits {
1541        Bits::one() << self.sign_field_shift()
1542    }
1543    /// get the amount by which the floating-point bits should be shifted right
1544    /// in order to extract the exponent field.
1545    ///
1546    /// the exponent field can be extracted using `(bits & exponent_field_mask) >> exponent_field_shift`
1547    #[inline]
1548    pub const fn exponent_field_shift(self) -> usize {
1549        self.mantissa_width
1550    }
1551    /// get the bitwise mask for the exponent field (before shifting to extract).
1552    ///
1553    /// the exponent field can be extracted using `(bits & exponent_field_mask) >> exponent_field_shift`
1554    pub fn exponent_field_mask<Bits: FloatBitsType>(self) -> Bits {
1555        ((Bits::one() << self.exponent_width) - Bits::one()) << self.exponent_field_shift()
1556    }
1557    /// get the amount by which the floating-point bits should be shifted right
1558    /// in order to extract the mantissa field.
1559    ///
1560    /// the mantissa field can be extracted using `(bits & mantissa_field_mask) >> mantissa_field_shift`
1561    #[inline]
1562    pub const fn mantissa_field_shift(self) -> usize {
1563        0
1564    }
1565    /// get the bitwise mask for the mantissa field (before shifting to extract).
1566    ///
1567    /// the mantissa field can be extracted using `(bits & mantissa_field_mask) >> mantissa_field_shift`
1568    pub fn mantissa_field_mask<Bits: FloatBitsType>(self) -> Bits {
1569        (Bits::one() << self.mantissa_width) - Bits::one()
1570    }
1571    /// get the maximum value of the mantissa field
1572    pub fn mantissa_field_max<Bits: FloatBitsType>(self) -> Bits {
1573        (Bits::one() << self.mantissa_width) - Bits::one()
1574    }
1575    /// get the minimum value the mantissa field can take on for normal floating-point numbers.
1576    pub fn mantissa_field_normal_min<Bits: FloatBitsType>(self) -> Bits {
1577        if self.has_implicit_leading_bit {
1578            Bits::zero()
1579        } else {
1580            Bits::one() << self.fraction_width()
1581        }
1582    }
1583    /// get the amount by which the floating-point bits should be shifted right
1584    /// in order to extract the mantissa field's MSB.
1585    ///
1586    /// the mantissa field's MSB can be extracted using `(bits & mantissa_field_msb_mask) >> mantissa_field_msb_shift`
1587    #[inline]
1588    pub const fn mantissa_field_msb_shift(self) -> usize {
1589        self.mantissa_width - 1
1590    }
1591    /// get the bitwise mask for the mantissa field's MSB (before shifting to extract).
1592    ///
1593    /// the mantissa field's MSB can be extracted using `(bits & mantissa_field_msb_mask) >> mantissa_field_msb_shift`
1594    pub fn mantissa_field_msb_mask<Bits: FloatBitsType>(self) -> Bits {
1595        Bits::one() << self.mantissa_field_msb_shift()
1596    }
1597    /// get the amount by which the exponent field is offset from the
1598    /// mathematical exponent for normal floating-point numbers.
1599    ///
1600    /// the mathematical exponent and the exponent field's values for normal
1601    /// floating-point numbers are related by the following equation:
1602    /// `mathematical_exponent + exponent_bias == exponent_field`
1603    pub fn exponent_bias<Bits: FloatBitsType>(self) -> Bits {
1604        if self.exponent_width == 0 {
1605            Bits::zero()
1606        } else {
1607            (Bits::one() << (self.exponent_width - 1)) - Bits::one()
1608        }
1609    }
1610    /// get the value used in the exponent field for infinities and NaNs
1611    pub fn exponent_inf_nan<Bits: FloatBitsType>(self) -> Bits {
1612        (Bits::one() << self.exponent_width) - Bits::one()
1613    }
1614    /// get the value used in the exponent field for zeros and subnormals
1615    pub fn exponent_zero_subnormal<Bits: FloatBitsType>(self) -> Bits {
1616        Bits::zero()
1617    }
1618    /// get the minimum value of the exponent field for normal floating-point numbers.
1619    ///
1620    /// the mathematical exponent and the exponent field's values for normal
1621    /// floating-point numbers are related by the following equation:
1622    /// `mathematical_exponent + exponent_bias == exponent_field`
1623    pub fn exponent_min_normal<Bits: FloatBitsType>(self) -> Bits {
1624        Bits::one()
1625    }
1626    /// get the maximum value of the exponent field for normal floating-point numbers.
1627    ///
1628    /// the mathematical exponent and the exponent field's values for normal
1629    /// floating-point numbers are related by the following equation:
1630    /// `mathematical_exponent + exponent_bias == exponent_field`
1631    pub fn exponent_max_normal<Bits: FloatBitsType>(self) -> Bits {
1632        self.exponent_inf_nan::<Bits>() - Bits::one()
1633    }
1634    /// get the mask for the whole floating-point format
1635    pub fn overall_mask<Bits: FloatBitsType>(self) -> Bits {
1636        self.sign_field_mask::<Bits>()
1637            | self.exponent_field_mask::<Bits>()
1638            | self.mantissa_field_mask::<Bits>()
1639    }
1640    fn fallback_debug(&self, f: &mut fmt::Formatter, is_standard: bool) -> fmt::Result {
1641        f.debug_struct("FloatProperties")
1642            .field("exponent_width", &self.exponent_width())
1643            .field("mantissa_width", &self.mantissa_width())
1644            .field("has_implicit_leading_bit", &self.has_implicit_leading_bit())
1645            .field("has_sign_bit", &self.has_sign_bit())
1646            .field("platform_properties", &self.platform_properties())
1647            .field("quiet_nan_format", &self.quiet_nan_format())
1648            .field("width", &self.width())
1649            .field("fraction_width", &self.fraction_width())
1650            .field("is_standard", &is_standard)
1651            .finish()
1652    }
1653}
1654
1655impl fmt::Debug for FloatProperties {
1656    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1657        let is_standard = self.is_standard();
1658        if !f.alternate() && is_standard {
1659            if self.platform_properties() == PlatformProperties::default() {
1660                match self.width() {
1661                    16 => f.write_str("FloatProperties::STANDARD_16"),
1662                    32 => f.write_str("FloatProperties::STANDARD_32"),
1663                    64 => f.write_str("FloatProperties::STANDARD_64"),
1664                    128 => f.write_str("FloatProperties::STANDARD_128"),
1665                    width => write!(f, "FloatProperties::standard({})", width),
1666                }
1667            } else {
1668                match self.width() {
1669                    16 => write!(
1670                        f,
1671                        "FloatProperties::standard_16_with_platform_properties({:?})",
1672                        self.platform_properties()
1673                    ),
1674                    32 => write!(
1675                        f,
1676                        "FloatProperties::standard_32_with_platform_properties({:?})",
1677                        self.platform_properties()
1678                    ),
1679                    64 => write!(
1680                        f,
1681                        "FloatProperties::standard_64_with_platform_properties({:?})",
1682                        self.platform_properties()
1683                    ),
1684                    128 => write!(
1685                        f,
1686                        "FloatProperties::standard_128_with_platform_properties({:?})",
1687                        self.platform_properties()
1688                    ),
1689                    width => write!(
1690                        f,
1691                        "FloatProperties::standard_with_platform_properties({}, {:?})",
1692                        width,
1693                        self.platform_properties()
1694                    ),
1695                }
1696            }
1697        } else {
1698            self.fallback_debug(f, is_standard)
1699        }
1700    }
1701}
1702
1703/// `FloatProperties` values along with the type used to represent bits for a floating-point format
1704pub trait FloatTraits: Clone + fmt::Debug + PartialEq {
1705    /// the type used to represent bits for a floating-point format
1706    type Bits: FloatBitsType;
1707    /// get the `FloatProperties` value
1708    fn properties(&self) -> FloatProperties;
1709}
1710
1711/// `FloatTraits` where `Bits = u16` and `properties` returns `FloatProperties::STANDARD_16`
1712#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, Default)]
1713pub struct F16Traits;
1714
1715/// `FloatTraits` where `Bits = u16` and `properties` returns
1716/// `FloatProperties::standard_16_with_platform_properties(self.0)`
1717#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)]
1718pub struct F16WithPlatformPropertiesTraits(pub PlatformProperties);
1719
1720/// `FloatTraits` where `Bits = u32` and `properties` returns `FloatProperties::STANDARD_32`
1721#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, Default)]
1722pub struct F32Traits;
1723
1724/// `FloatTraits` where `Bits = u32` and `properties` returns
1725/// `FloatProperties::standard_32_with_platform_properties(self.0)`
1726#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)]
1727pub struct F32WithPlatformPropertiesTraits(pub PlatformProperties);
1728
1729/// `FloatTraits` where `Bits = u64` and `properties` returns `FloatProperties::STANDARD_64`
1730#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, Default)]
1731pub struct F64Traits;
1732
1733/// `FloatTraits` where `Bits = u64` and `properties` returns
1734/// `FloatProperties::standard_64_with_platform_properties(self.0)`
1735#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)]
1736pub struct F64WithPlatformPropertiesTraits(pub PlatformProperties);
1737
1738/// `FloatTraits` where `Bits = u128` and `properties` returns `FloatProperties::STANDARD_128`
1739#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, Default)]
1740pub struct F128Traits;
1741
1742/// `FloatTraits` where `Bits = u128` and `properties` returns
1743/// `FloatProperties::standard_128_with_platform_properties(self.0)`
1744#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)]
1745pub struct F128WithPlatformPropertiesTraits(pub PlatformProperties);
1746
1747impl FloatTraits for FloatProperties {
1748    type Bits = BigUint;
1749    fn properties(&self) -> FloatProperties {
1750        *self
1751    }
1752}
1753
1754impl FloatTraits for F16Traits {
1755    type Bits = u16;
1756    fn properties(&self) -> FloatProperties {
1757        FloatProperties::STANDARD_16
1758    }
1759}
1760
1761impl FloatTraits for F16WithPlatformPropertiesTraits {
1762    type Bits = u16;
1763    fn properties(&self) -> FloatProperties {
1764        FloatProperties::standard_16_with_platform_properties(self.0)
1765    }
1766}
1767
1768impl FloatTraits for F32Traits {
1769    type Bits = u32;
1770    fn properties(&self) -> FloatProperties {
1771        FloatProperties::STANDARD_32
1772    }
1773}
1774
1775impl FloatTraits for F32WithPlatformPropertiesTraits {
1776    type Bits = u32;
1777    fn properties(&self) -> FloatProperties {
1778        FloatProperties::standard_32_with_platform_properties(self.0)
1779    }
1780}
1781
1782impl FloatTraits for F64Traits {
1783    type Bits = u64;
1784    fn properties(&self) -> FloatProperties {
1785        FloatProperties::STANDARD_64
1786    }
1787}
1788
1789impl FloatTraits for F64WithPlatformPropertiesTraits {
1790    type Bits = u64;
1791    fn properties(&self) -> FloatProperties {
1792        FloatProperties::standard_64_with_platform_properties(self.0)
1793    }
1794}
1795
1796impl FloatTraits for F128Traits {
1797    type Bits = u128;
1798    fn properties(&self) -> FloatProperties {
1799        FloatProperties::STANDARD_128
1800    }
1801}
1802
1803impl FloatTraits for F128WithPlatformPropertiesTraits {
1804    type Bits = u128;
1805    fn properties(&self) -> FloatProperties {
1806        FloatProperties::standard_128_with_platform_properties(self.0)
1807    }
1808}
1809
1810struct RoundedMantissa {
1811    inexact: bool,
1812    exponent: i64,
1813    mantissa: BigInt,
1814}
1815
1816impl RoundedMantissa {
1817    fn new(
1818        value: &RealAlgebraicNumber,
1819        exponent: i64,
1820        sign: Sign,
1821        rounding_mode: RoundingMode,
1822        properties: FloatProperties,
1823        max_mantissa: &BigInt,
1824    ) -> Self {
1825        assert!(!value.is_negative());
1826        let ulp_shift = exponent
1827            - properties
1828                .fraction_width()
1829                .to_i64()
1830                .expect("fraction_width doesn't fit in i64");
1831        let ulp = if ulp_shift < 0 {
1832            let shift = (-ulp_shift)
1833                .to_usize()
1834                .expect("ulp_shift doesn't fit in usize");
1835            Ratio::new(BigInt::one(), BigInt::one() << shift)
1836        } else {
1837            Ratio::from(
1838                BigInt::one() << ulp_shift.to_usize().expect("exponent doesn't fit in usize"),
1839            )
1840        };
1841        let value_in_ulps = value / RealAlgebraicNumber::from(ulp);
1842        let lower_float_exponent = exponent;
1843        let lower_float_mantissa = value_in_ulps.to_integer_floor();
1844        let remainder_in_ulps =
1845            value_in_ulps - RealAlgebraicNumber::from(lower_float_mantissa.clone());
1846        assert!(!lower_float_mantissa.is_negative());
1847        assert!(lower_float_mantissa <= *max_mantissa);
1848        if remainder_in_ulps.is_zero() {
1849            Self {
1850                inexact: false,
1851                exponent: lower_float_exponent,
1852                mantissa: lower_float_mantissa,
1853            }
1854        } else {
1855            let mut upper_float_mantissa = &lower_float_mantissa + 1i32;
1856            let mut upper_float_exponent = lower_float_exponent;
1857            if upper_float_mantissa > *max_mantissa {
1858                upper_float_mantissa >>= 1;
1859                upper_float_exponent += 1;
1860            }
1861            match (rounding_mode, sign) {
1862                (RoundingMode::TiesToEven, _) | (RoundingMode::TiesToAway, _) => {
1863                    match remainder_in_ulps.cmp(&RealAlgebraicNumber::from(Ratio::new(1, 2))) {
1864                        Ordering::Less => Self {
1865                            inexact: true,
1866                            exponent: lower_float_exponent,
1867                            mantissa: lower_float_mantissa,
1868                        },
1869                        Ordering::Equal => {
1870                            if rounding_mode == RoundingMode::TiesToAway
1871                                || lower_float_mantissa.is_odd()
1872                            {
1873                                Self {
1874                                    inexact: true,
1875                                    exponent: upper_float_exponent,
1876                                    mantissa: upper_float_mantissa,
1877                                }
1878                            } else {
1879                                Self {
1880                                    inexact: true,
1881                                    exponent: lower_float_exponent,
1882                                    mantissa: lower_float_mantissa,
1883                                }
1884                            }
1885                        }
1886                        Ordering::Greater => Self {
1887                            inexact: true,
1888                            exponent: upper_float_exponent,
1889                            mantissa: upper_float_mantissa,
1890                        },
1891                    }
1892                }
1893                (RoundingMode::TowardZero, _) => Self {
1894                    inexact: true,
1895                    exponent: lower_float_exponent,
1896                    mantissa: lower_float_mantissa,
1897                },
1898                (RoundingMode::TowardNegative, Sign::Negative)
1899                | (RoundingMode::TowardPositive, Sign::Positive) => Self {
1900                    inexact: true,
1901                    exponent: upper_float_exponent,
1902                    mantissa: upper_float_mantissa,
1903                },
1904                (RoundingMode::TowardNegative, Sign::Positive)
1905                | (RoundingMode::TowardPositive, Sign::Negative) => Self {
1906                    inexact: true,
1907                    exponent: lower_float_exponent,
1908                    mantissa: lower_float_mantissa,
1909                },
1910            }
1911        }
1912    }
1913}
1914
1915python_enum! {
1916    #[pyenum(module = simple_soft_float, repr = u8, test_fn = test_up_or_down_enum)]
1917    /// select Up or Down
1918    pub enum UpOrDown {
1919        /// Up
1920        Up,
1921        /// Down
1922        Down,
1923    }
1924}
1925
1926impl Default for UpOrDown {
1927    fn default() -> Self {
1928        Self::Up
1929    }
1930}
1931
1932impl From<UpOrDown> for Sign {
1933    fn from(up_or_down: UpOrDown) -> Sign {
1934        match up_or_down {
1935            UpOrDown::Up => Sign::Positive,
1936            UpOrDown::Down => Sign::Negative,
1937        }
1938    }
1939}
1940
1941/// the floating-point type with the specified `FloatTraits`
1942#[derive(Copy, Clone)]
1943pub struct Float<FT: FloatTraits> {
1944    traits: FT,
1945    bits: FT::Bits,
1946}
1947
1948impl<FT: FloatTraits + Default> Default for Float<FT> {
1949    fn default() -> Self {
1950        Self::positive_zero()
1951    }
1952}
1953
1954macro_rules! impl_from_int_type {
1955    ($from_int_with_traits:ident, $from_int:ident, $int:ident) => {
1956        /// convert from integer to floating-point
1957        pub fn $from_int_with_traits(
1958            value: $int,
1959            rounding_mode: Option<RoundingMode>,
1960            fp_state: Option<&mut FPState>,
1961            traits: FT,
1962        ) -> Self {
1963            Self::from_real_algebraic_number_with_traits(
1964                &value.into(),
1965                rounding_mode,
1966                fp_state,
1967                traits,
1968            )
1969        }
1970        /// convert from integer to floating-point
1971        pub fn $from_int(
1972            value: $int,
1973            rounding_mode: Option<RoundingMode>,
1974            fp_state: Option<&mut FPState>,
1975        ) -> Self
1976        where
1977            FT: Default,
1978        {
1979            Self::$from_int_with_traits(value, rounding_mode, fp_state, FT::default())
1980        }
1981    };
1982}
1983
1984macro_rules! impl_to_int_type {
1985    ($name:ident, $from_bigint:ident, $int:ident) => {
1986        /// convert from floating-point to integer
1987        pub fn $name(
1988            &self,
1989            exact: bool,
1990            rounding_mode: Option<RoundingMode>,
1991            fp_state: Option<&mut FPState>,
1992        ) -> Option<$int> {
1993            let mut default_fp_state = FPState::default();
1994            let fp_state = fp_state.unwrap_or(&mut default_fp_state);
1995            let old_status_flags = fp_state.status_flags;
1996            if let Some(retval) = self.round_to_integer(exact, rounding_mode, Some(fp_state)).and_then(|v| v.$from_bigint()) {
1997                Some(retval)
1998            } else {
1999                // ignore possible INEXACT flags
2000                fp_state.status_flags = old_status_flags | StatusFlags::INVALID_OPERATION;
2001                None
2002            }
2003        }
2004    };
2005}
2006
2007impl<Bits: FloatBitsType, FT: FloatTraits<Bits = Bits>> Float<FT> {
2008    fn check_bits(bits: Bits, traits: &FT) -> Bits {
2009        assert!(
2010            traits.properties().overall_mask::<Bits>() & &bits == bits,
2011            "bits out of range"
2012        );
2013        bits
2014    }
2015    /// construct `Float` from bits
2016    pub fn from_bits_and_traits(bits: Bits, traits: FT) -> Self {
2017        Self {
2018            bits: Self::check_bits(bits, &traits),
2019            traits,
2020        }
2021    }
2022    /// construct `Float` from bits
2023    pub fn from_bits(bits: Bits) -> Self
2024    where
2025        FT: Default,
2026    {
2027        Self::from_bits_and_traits(bits, FT::default())
2028    }
2029    /// get the underlying bits
2030    pub fn bits(&self) -> &Bits {
2031        &self.bits
2032    }
2033    /// set the underlying bits
2034    pub fn set_bits(&mut self, bits: Bits) {
2035        self.bits = Self::check_bits(bits, &self.traits);
2036    }
2037    /// get the `FloatTraits`
2038    pub fn traits(&self) -> &FT {
2039        &self.traits
2040    }
2041    /// get the bits and `FloatTraits`
2042    pub fn into_bits_and_traits(self) -> (Bits, FT) {
2043        (self.bits, self.traits)
2044    }
2045    /// get the underlying bits
2046    pub fn into_bits(self) -> Bits {
2047        self.bits
2048    }
2049    /// get the `FloatTraits`
2050    pub fn into_traits(self) -> FT {
2051        self.traits
2052    }
2053    /// get the `FloatProperties`
2054    pub fn properties(&self) -> FloatProperties {
2055        self.traits.properties()
2056    }
2057    /// get the sign
2058    pub fn sign(&self) -> Sign {
2059        let properties = self.properties();
2060        if properties.has_sign_bit() {
2061            if (self.bits.clone() >> properties.sign_field_shift()).is_zero() {
2062                Sign::Positive
2063            } else {
2064                Sign::Negative
2065            }
2066        } else {
2067            Sign::Positive
2068        }
2069    }
2070    fn xor_bits(&mut self, bits: Bits) {
2071        BitXorAssign::<Bits>::bitxor_assign(&mut self.bits, bits);
2072    }
2073    fn or_bits(&mut self, bits: Bits) {
2074        BitOrAssign::<Bits>::bitor_assign(&mut self.bits, bits);
2075    }
2076    fn and_not_bits(&mut self, bits: Bits) {
2077        BitOrAssign::<&Bits>::bitor_assign(&mut self.bits, &bits);
2078        self.xor_bits(bits)
2079    }
2080    /// set the sign
2081    pub fn set_sign(&mut self, sign: Sign) {
2082        let properties = self.properties();
2083        if !properties.has_sign_bit() {
2084            assert_eq!(sign, Sign::Positive);
2085            return;
2086        }
2087        match sign {
2088            Sign::Positive => self.and_not_bits(properties.sign_field_mask()),
2089            Sign::Negative => self.or_bits(properties.sign_field_mask()),
2090        }
2091    }
2092    /// toggle the sign
2093    pub fn toggle_sign(&mut self) {
2094        let properties = self.properties();
2095        assert!(properties.has_sign_bit());
2096        self.xor_bits(properties.sign_field_mask());
2097    }
2098    /// get the exponent field
2099    ///
2100    /// the mathematical exponent and the exponent field's values for normal
2101    /// floating-point numbers are related by the following equation:
2102    /// `mathematical_exponent + exponent_bias == exponent_field`
2103    pub fn exponent_field(&self) -> Bits {
2104        let properties = self.properties();
2105        (properties.exponent_field_mask::<Bits>() & &self.bits) >> properties.exponent_field_shift()
2106    }
2107    /// set the exponent field
2108    ///
2109    /// the mathematical exponent and the exponent field's values for normal
2110    /// floating-point numbers are related by the following equation:
2111    /// `mathematical_exponent + exponent_bias == exponent_field`
2112    pub fn set_exponent_field(&mut self, mut exponent: Bits) {
2113        let properties = self.properties();
2114        exponent <<= properties.exponent_field_shift();
2115        let mask: Bits = properties.exponent_field_mask();
2116        assert!(
2117            mask.clone() & &exponent == exponent,
2118            "exponent out of range"
2119        );
2120        self.and_not_bits(mask);
2121        self.or_bits(exponent);
2122    }
2123    /// get the mantissa field
2124    pub fn mantissa_field(&self) -> Bits {
2125        let properties = self.properties();
2126        (properties.mantissa_field_mask::<Bits>() & &self.bits) >> properties.mantissa_field_shift()
2127    }
2128    /// set the mantissa field
2129    pub fn set_mantissa_field(&mut self, mut mantissa: Bits) {
2130        let properties = self.properties();
2131        mantissa <<= properties.mantissa_field_shift();
2132        let mask: Bits = properties.mantissa_field_mask();
2133        assert!(
2134            mask.clone() & &mantissa == mantissa,
2135            "mantissa out of range"
2136        );
2137        self.and_not_bits(mask);
2138        self.or_bits(mantissa);
2139    }
2140    /// get the mantissa field's MSB
2141    pub fn mantissa_field_msb(&self) -> bool {
2142        let properties = self.properties();
2143        !(properties.mantissa_field_msb_mask::<Bits>() & &self.bits).is_zero()
2144    }
2145    /// set the mantissa field's MSB
2146    pub fn set_mantissa_field_msb(&mut self, mantissa_msb: bool) {
2147        let properties = self.properties();
2148        if mantissa_msb {
2149            self.or_bits(properties.mantissa_field_msb_mask());
2150        } else {
2151            self.and_not_bits(properties.mantissa_field_msb_mask());
2152        }
2153    }
2154    /// calculate the `FloatClass`
2155    pub fn class(&self) -> FloatClass {
2156        let properties = self.properties();
2157        let sign = self.sign();
2158        let mut exponent_field = self.exponent_field();
2159        let mut mantissa_field = self.mantissa_field();
2160        let retval = if exponent_field == properties.exponent_zero_subnormal() {
2161            if mantissa_field.is_zero() {
2162                FloatClass::PositiveZero
2163            } else {
2164                FloatClass::PositiveSubnormal
2165            }
2166        } else if exponent_field == properties.exponent_inf_nan() {
2167            if mantissa_field.is_zero() {
2168                FloatClass::PositiveInfinity
2169            } else if properties
2170                .quiet_nan_format()
2171                .is_nan_quiet(self.mantissa_field_msb())
2172            {
2173                FloatClass::QuietNaN
2174            } else {
2175                FloatClass::SignalingNaN
2176            }
2177        } else if properties.has_implicit_leading_bit() {
2178            FloatClass::PositiveNormal
2179        } else if mantissa_field.is_zero() {
2180            FloatClass::PositiveZero
2181        } else {
2182            loop {
2183                if (properties.mantissa_field_msb_mask::<Bits>() & &mantissa_field).is_zero() {
2184                    mantissa_field <<= 1;
2185                    exponent_field -= Bits::one();
2186                    if exponent_field == properties.exponent_zero_subnormal() {
2187                        break FloatClass::PositiveSubnormal;
2188                    }
2189                } else {
2190                    break FloatClass::PositiveNormal;
2191                }
2192            }
2193        };
2194        match sign {
2195            Sign::Positive => retval,
2196            Sign::Negative => -retval,
2197        }
2198    }
2199    /// return `true` if `self.class()` is `NegativeInfinity`
2200    #[inline]
2201    pub fn is_negative_infinity(&self) -> bool {
2202        self.class().is_negative_infinity()
2203    }
2204    /// return `true` if `self.class()` is `NegativeNormal`
2205    #[inline]
2206    pub fn is_negative_normal(&self) -> bool {
2207        self.class().is_negative_normal()
2208    }
2209    /// return `true` if `self.class()` is `NegativeSubnormal`
2210    #[inline]
2211    pub fn is_negative_subnormal(&self) -> bool {
2212        self.class().is_negative_subnormal()
2213    }
2214    /// return `true` if `self.class()` is `NegativeZero`
2215    #[inline]
2216    pub fn is_negative_zero(&self) -> bool {
2217        self.class().is_negative_zero()
2218    }
2219    /// return `true` if `self.class()` is `PositiveInfinity`
2220    #[inline]
2221    pub fn is_positive_infinity(&self) -> bool {
2222        self.class().is_positive_infinity()
2223    }
2224    /// return `true` if `self.class()` is `PositiveNormal`
2225    #[inline]
2226    pub fn is_positive_normal(&self) -> bool {
2227        self.class().is_positive_normal()
2228    }
2229    /// return `true` if `self.class()` is `PositiveSubnormal`
2230    #[inline]
2231    pub fn is_positive_subnormal(&self) -> bool {
2232        self.class().is_positive_subnormal()
2233    }
2234    /// return `true` if `self.class()` is `PositiveZero`
2235    #[inline]
2236    pub fn is_positive_zero(&self) -> bool {
2237        self.class().is_positive_zero()
2238    }
2239    /// return `true` if `self.class()` is `QuietNaN`
2240    #[inline]
2241    pub fn is_quiet_nan(&self) -> bool {
2242        self.class().is_quiet_nan()
2243    }
2244    /// return `true` if `self.class()` is `SignalingNaN`
2245    #[inline]
2246    pub fn is_signaling_nan(&self) -> bool {
2247        self.class().is_signaling_nan()
2248    }
2249    /// return `true` if `self` is infinity
2250    #[inline]
2251    pub fn is_infinity(&self) -> bool {
2252        self.class().is_infinity()
2253    }
2254    /// return `true` if `self.class()` is `NegativeNormal` or `PositiveNormal`
2255    #[inline]
2256    pub fn is_normal(&self) -> bool {
2257        self.class().is_normal()
2258    }
2259    /// return `true` if `self` is subnormal
2260    #[inline]
2261    pub fn is_subnormal(&self) -> bool {
2262        self.class().is_subnormal()
2263    }
2264    /// return `true` if `self` is zero
2265    #[inline]
2266    pub fn is_zero(&self) -> bool {
2267        self.class().is_zero()
2268    }
2269    /// return `true` if `self` is NaN
2270    #[inline]
2271    pub fn is_nan(&self) -> bool {
2272        self.class().is_nan()
2273    }
2274    /// return `true` if `self` is finite (not NaN or infinity)
2275    #[inline]
2276    pub fn is_finite(&self) -> bool {
2277        self.class().is_finite()
2278    }
2279    /// return `true` if `self` is subnormal or zero
2280    #[inline]
2281    pub fn is_subnormal_or_zero(&self) -> bool {
2282        self.class().is_subnormal_or_zero()
2283    }
2284    /// get the mathematical value of `self` as a `Ratio<BigInt>`.
2285    /// if `self` is NaN or infinite, returns `None`.
2286    pub fn to_ratio(&self) -> Option<Ratio<BigInt>> {
2287        if !self.is_finite() {
2288            return None;
2289        }
2290        let properties = self.properties();
2291        let sign = self.sign();
2292        let exponent_field = self.exponent_field();
2293        let mantissa_field = self.mantissa_field();
2294        let mut mantissa: BigInt = mantissa_field.into();
2295        let mut exponent = exponent_field
2296            .to_i64()
2297            .expect("exponent_field doesn't fit in i64");
2298        if self.is_subnormal_or_zero() {
2299            exponent = properties
2300                .exponent_min_normal::<Bits>()
2301                .to_i64()
2302                .expect("exponent_field doesn't fit in i64");
2303        } else if properties.has_implicit_leading_bit() {
2304            mantissa |= BigInt::one() << properties.fraction_width();
2305        }
2306        exponent -= properties
2307            .exponent_bias::<Bits>()
2308            .to_i64()
2309            .expect("exponent bias doesn't fit in i64");
2310        exponent -= properties
2311            .fraction_width()
2312            .to_i64()
2313            .expect("fraction_width doesn't fit in i64");
2314        let mut retval = if exponent.is_negative() {
2315            let shift = (-exponent)
2316                .to_usize()
2317                .expect("exponent doesn't fit in usize");
2318            Ratio::new(mantissa, BigInt::one() << shift)
2319        } else {
2320            Ratio::from(mantissa << exponent.to_usize().expect("exponent doesn't fit in usize"))
2321        };
2322        if sign == Sign::Negative {
2323            retval = -retval;
2324        }
2325        Some(retval)
2326    }
2327    /// get the mathematical value of `self` as a `RealAlgebraicNumber`.
2328    /// if `self` is NaN or infinite, returns `None`.
2329    pub fn to_real_algebraic_number(&self) -> Option<RealAlgebraicNumber> {
2330        self.to_ratio().map(Into::into)
2331    }
2332    /// get the positive zero value
2333    pub fn positive_zero_with_traits(traits: FT) -> Self {
2334        Self::from_bits_and_traits(Bits::zero(), traits)
2335    }
2336    /// get the positive zero value
2337    pub fn positive_zero() -> Self
2338    where
2339        FT: Default,
2340    {
2341        Self::positive_zero_with_traits(FT::default())
2342    }
2343    /// get the negative zero value
2344    pub fn negative_zero_with_traits(traits: FT) -> Self {
2345        let properties = traits.properties();
2346        assert!(properties.has_sign_bit());
2347        let bits = properties.sign_field_mask::<Bits>();
2348        Self::from_bits_and_traits(bits, traits)
2349    }
2350    /// get the negative zero value
2351    pub fn negative_zero() -> Self
2352    where
2353        FT: Default,
2354    {
2355        Self::negative_zero_with_traits(FT::default())
2356    }
2357    /// get the zero with sign `sign`
2358    pub fn signed_zero_with_traits(sign: Sign, traits: FT) -> Self {
2359        match sign {
2360            Sign::Positive => Self::positive_zero_with_traits(traits),
2361            Sign::Negative => Self::negative_zero_with_traits(traits),
2362        }
2363    }
2364    /// get the zero with sign `sign`
2365    pub fn signed_zero(sign: Sign) -> Self
2366    where
2367        FT: Default,
2368    {
2369        Self::signed_zero_with_traits(sign, FT::default())
2370    }
2371    /// get the positive infinity value
2372    pub fn positive_infinity_with_traits(traits: FT) -> Self {
2373        let properties = traits.properties();
2374        let mut retval = Self::positive_zero_with_traits(traits);
2375        retval.set_exponent_field(properties.exponent_inf_nan::<Bits>());
2376        retval
2377    }
2378    /// get the positive infinity value
2379    pub fn positive_infinity() -> Self
2380    where
2381        FT: Default,
2382    {
2383        Self::positive_infinity_with_traits(FT::default())
2384    }
2385    /// get the negative infinity value
2386    pub fn negative_infinity_with_traits(traits: FT) -> Self {
2387        let properties = traits.properties();
2388        let mut retval = Self::negative_zero_with_traits(traits);
2389        retval.set_exponent_field(properties.exponent_inf_nan::<Bits>());
2390        retval
2391    }
2392    /// get the negative infinity value
2393    pub fn negative_infinity() -> Self
2394    where
2395        FT: Default,
2396    {
2397        Self::negative_infinity_with_traits(FT::default())
2398    }
2399    /// get the infinity with sign `sign`
2400    pub fn signed_infinity_with_traits(sign: Sign, traits: FT) -> Self {
2401        match sign {
2402            Sign::Positive => Self::positive_infinity_with_traits(traits),
2403            Sign::Negative => Self::negative_infinity_with_traits(traits),
2404        }
2405    }
2406    /// get the infinity with sign `sign`
2407    pub fn signed_infinity(sign: Sign) -> Self
2408    where
2409        FT: Default,
2410    {
2411        Self::signed_infinity_with_traits(sign, FT::default())
2412    }
2413    /// get the canonical quiet NaN, which is also just the canonical NaN
2414    pub fn quiet_nan_with_traits(traits: FT) -> Self {
2415        let properties = traits.properties();
2416        let mut retval = Self::positive_zero_with_traits(traits);
2417        retval.set_exponent_field(properties.exponent_inf_nan::<Bits>());
2418        match properties.quiet_nan_format() {
2419            QuietNaNFormat::Standard => retval.set_mantissa_field_msb(true),
2420            QuietNaNFormat::MIPSLegacy => {
2421                retval.set_mantissa_field(properties.mantissa_field_max());
2422                retval.set_mantissa_field_msb(false);
2423            }
2424        }
2425        retval
2426    }
2427    /// get the canonical quiet NaN, which is also just the canonical NaN
2428    pub fn quiet_nan() -> Self
2429    where
2430        FT: Default,
2431    {
2432        Self::quiet_nan_with_traits(FT::default())
2433    }
2434    /// get the canonical signaling NaN
2435    pub fn signaling_nan_with_traits(traits: FT) -> Self {
2436        let properties = traits.properties();
2437        let mut retval = Self::positive_zero_with_traits(traits);
2438        retval.set_exponent_field(properties.exponent_inf_nan::<Bits>());
2439        match properties.quiet_nan_format() {
2440            QuietNaNFormat::Standard => retval.set_mantissa_field(Bits::one()),
2441            QuietNaNFormat::MIPSLegacy => retval.set_mantissa_field_msb(true),
2442        }
2443        retval
2444    }
2445    /// get the canonical signaling NaN
2446    pub fn signaling_nan() -> Self
2447    where
2448        FT: Default,
2449    {
2450        Self::signaling_nan_with_traits(FT::default())
2451    }
2452    /// convert `self` into a quiet NaN
2453    pub fn into_quiet_nan(mut self) -> Self {
2454        let properties = self.properties();
2455        self.set_exponent_field(properties.exponent_inf_nan::<Bits>());
2456        // FIXME: handle nan propagation properly
2457        match properties.quiet_nan_format() {
2458            QuietNaNFormat::Standard => self.set_mantissa_field_msb(true),
2459            QuietNaNFormat::MIPSLegacy => return Self::quiet_nan_with_traits(self.traits),
2460        }
2461        self
2462    }
2463    /// convert `self` into a quiet NaN
2464    pub fn to_quiet_nan(&self) -> Self {
2465        self.clone().into_quiet_nan()
2466    }
2467    /// get the largest finite value with sign `sign`
2468    pub fn signed_max_normal_with_traits(sign: Sign, traits: FT) -> Self {
2469        let properties = traits.properties();
2470        let mut retval = Self::signed_zero_with_traits(sign, traits);
2471        retval.set_mantissa_field(properties.mantissa_field_max());
2472        retval.set_exponent_field(properties.exponent_max_normal());
2473        retval
2474    }
2475    /// get the largest finite value with sign `sign`
2476    pub fn signed_max_normal(sign: Sign) -> Self
2477    where
2478        FT: Default,
2479    {
2480        Self::signed_max_normal_with_traits(sign, FT::default())
2481    }
2482    /// get the subnormal value closest to zero with sign `sign`
2483    pub fn signed_min_subnormal_with_traits(sign: Sign, traits: FT) -> Self {
2484        let properties = traits.properties();
2485        let mut retval = Self::signed_zero_with_traits(sign, traits);
2486        retval.set_mantissa_field(Bits::one());
2487        retval.set_exponent_field(properties.exponent_zero_subnormal());
2488        retval
2489    }
2490    /// get the subnormal value closest to zero with sign `sign`
2491    pub fn signed_min_subnormal(sign: Sign) -> Self
2492    where
2493        FT: Default,
2494    {
2495        Self::signed_min_subnormal_with_traits(sign, FT::default())
2496    }
2497    /// round from a `RealAlgebraicNumber` into a floating-point value.
2498    pub fn from_real_algebraic_number_with_traits(
2499        value: &RealAlgebraicNumber,
2500        rounding_mode: Option<RoundingMode>,
2501        fp_state: Option<&mut FPState>,
2502        traits: FT,
2503    ) -> Self {
2504        let mut default_fp_state = FPState::default();
2505        let fp_state = fp_state.unwrap_or(&mut default_fp_state);
2506        let rounding_mode = rounding_mode.unwrap_or(fp_state.rounding_mode);
2507        let properties = traits.properties();
2508        let sign = if value.is_positive() {
2509            Sign::Positive
2510        } else if !properties.has_sign_bit() {
2511            if !value.is_zero() {
2512                fp_state.status_flags |= StatusFlags::INEXACT | StatusFlags::UNDERFLOW;
2513            }
2514            return Self::positive_zero_with_traits(traits);
2515        } else {
2516            Sign::Negative
2517        };
2518        let value = value.abs();
2519        let exponent = if let Some(v) = value.checked_floor_log2() {
2520            v
2521        } else {
2522            return Self::positive_zero_with_traits(traits);
2523        };
2524        let exponent_bias = properties.exponent_bias::<Bits>();
2525        let exponent_bias_i64 = exponent_bias
2526            .to_i64()
2527            .expect("exponent_bias doesn't fit in i64");
2528        let exponent_max = properties
2529            .exponent_max_normal::<Bits>()
2530            .to_i64()
2531            .expect("exponent_max_normal doesn't fit in i64")
2532            - exponent_bias_i64;
2533        if exponent > exponent_max {
2534            fp_state.status_flags |= StatusFlags::INEXACT | StatusFlags::OVERFLOW;
2535            match (rounding_mode, sign) {
2536                (RoundingMode::TowardNegative, Sign::Positive)
2537                | (RoundingMode::TowardPositive, Sign::Negative)
2538                | (RoundingMode::TowardZero, _) => {
2539                    return Self::signed_max_normal_with_traits(sign, traits);
2540                }
2541                (RoundingMode::TowardNegative, Sign::Negative)
2542                | (RoundingMode::TowardPositive, Sign::Positive)
2543                | (RoundingMode::TiesToEven, _)
2544                | (RoundingMode::TiesToAway, _) => {
2545                    return Self::signed_infinity_with_traits(sign, traits);
2546                }
2547            }
2548        }
2549        let exponent_min = properties
2550            .exponent_min_normal::<Bits>()
2551            .to_i64()
2552            .expect("exponent_min_normal doesn't fit in i64")
2553            - exponent_bias_i64;
2554        let min_normal_mantissa = BigInt::one() << properties.fraction_width();
2555        let mut max_mantissa: BigInt = properties.mantissa_field_max::<BigUint>().into();
2556        max_mantissa |= &min_normal_mantissa;
2557        let RoundedMantissa {
2558            inexact,
2559            exponent: retval_exponent,
2560            mantissa: mut retval_mantissa,
2561        } = RoundedMantissa::new(
2562            &value,
2563            exponent.max(exponent_min),
2564            sign,
2565            rounding_mode,
2566            properties,
2567            &max_mantissa,
2568        );
2569        let check_for_underflow = match fp_state.exception_handling_mode {
2570            ExceptionHandlingMode::IgnoreExactUnderflow => inexact,
2571            ExceptionHandlingMode::SignalExactUnderflow => true,
2572        };
2573        if exponent < exponent_min && check_for_underflow {
2574            let tiny = match fp_state.tininess_detection_mode {
2575                TininessDetectionMode::BeforeRounding => true,
2576                TininessDetectionMode::AfterRounding => {
2577                    if retval_mantissa < min_normal_mantissa {
2578                        true
2579                    } else {
2580                        RoundedMantissa::new(
2581                            &value,
2582                            exponent_min - 1,
2583                            sign,
2584                            rounding_mode,
2585                            properties,
2586                            &max_mantissa,
2587                        )
2588                        .exponent
2589                            < exponent_min
2590                    }
2591                }
2592            };
2593            if tiny {
2594                fp_state.status_flags |= StatusFlags::UNDERFLOW;
2595            }
2596        }
2597        if inexact {
2598            fp_state.status_flags |= StatusFlags::INEXACT;
2599        }
2600        if retval_exponent > exponent_max {
2601            fp_state.status_flags |= StatusFlags::OVERFLOW;
2602            return Self::signed_infinity_with_traits(sign, traits);
2603        }
2604        let mut retval = Self::signed_zero_with_traits(sign, traits);
2605        if retval_mantissa < min_normal_mantissa {
2606            assert_eq!(retval_exponent, exponent_min);
2607            retval.set_exponent_field(properties.exponent_zero_subnormal());
2608            retval.set_mantissa_field(
2609                Bits::from_bigint(&retval_mantissa).expect("retval_mantissa doesn't fit in Bits"),
2610            );
2611        } else {
2612            if properties.has_implicit_leading_bit() {
2613                retval_mantissa &= !&min_normal_mantissa;
2614                assert!(retval_mantissa < min_normal_mantissa);
2615            }
2616            let exponent_field = Bits::from_i64(retval_exponent + exponent_bias_i64)
2617                .expect("exponent doesn't fit in Bits");
2618            retval.set_exponent_field(exponent_field);
2619            retval.set_mantissa_field(
2620                Bits::from_bigint(&retval_mantissa).expect("retval_mantissa doesn't fit in Bits"),
2621            );
2622        }
2623        retval
2624    }
2625    /// round from a `RealAlgebraicNumber` into a floating-point value.
2626    pub fn from_real_algebraic_number(
2627        value: &RealAlgebraicNumber,
2628        rounding_mode: Option<RoundingMode>,
2629        fp_state: Option<&mut FPState>,
2630    ) -> Self
2631    where
2632        FT: Default,
2633    {
2634        Self::from_real_algebraic_number_with_traits(value, rounding_mode, fp_state, FT::default())
2635    }
2636    fn add_or_sub(
2637        &self,
2638        rhs: &Self,
2639        rounding_mode: Option<RoundingMode>,
2640        fp_state: Option<&mut FPState>,
2641        is_sub: bool,
2642    ) -> Self {
2643        assert_eq!(self.traits, rhs.traits);
2644        let properties = self.properties();
2645        let mut default_fp_state = FPState::default();
2646        let fp_state = fp_state.unwrap_or(&mut default_fp_state);
2647        let rounding_mode = rounding_mode.unwrap_or(fp_state.rounding_mode);
2648        let self_class = self.class();
2649        let mut rhs_class = rhs.class();
2650        if is_sub {
2651            rhs_class = -rhs_class;
2652        }
2653        match (self_class, rhs_class) {
2654            (FloatClass::SignalingNaN, _)
2655            | (FloatClass::QuietNaN, _)
2656            | (_, FloatClass::SignalingNaN)
2657            | (_, FloatClass::QuietNaN) => {
2658                if self_class.is_signaling_nan() || rhs_class.is_signaling_nan() {
2659                    fp_state.status_flags |= StatusFlags::INVALID_OPERATION;
2660                }
2661                match properties
2662                    .platform_properties
2663                    .std_bin_ops_nan_propagation_mode
2664                    .calculate_propagation_results(self_class, rhs_class)
2665                {
2666                    BinaryNaNPropagationResults::First => self.to_quiet_nan(),
2667                    BinaryNaNPropagationResults::Second => rhs.to_quiet_nan(),
2668                    BinaryNaNPropagationResults::Canonical => {
2669                        Self::quiet_nan_with_traits(self.traits.clone())
2670                    }
2671                }
2672            }
2673            (FloatClass::NegativeInfinity, FloatClass::PositiveInfinity)
2674            | (FloatClass::PositiveInfinity, FloatClass::NegativeInfinity) => {
2675                fp_state.status_flags |= StatusFlags::INVALID_OPERATION;
2676                Self::quiet_nan_with_traits(self.traits.clone())
2677            }
2678            (FloatClass::PositiveInfinity, _) | (_, FloatClass::PositiveInfinity) => {
2679                Self::positive_infinity_with_traits(self.traits.clone())
2680            }
2681            (FloatClass::NegativeInfinity, _) | (_, FloatClass::NegativeInfinity) => {
2682                Self::negative_infinity_with_traits(self.traits.clone())
2683            }
2684            (FloatClass::PositiveZero, FloatClass::PositiveZero) => {
2685                Self::positive_zero_with_traits(self.traits.clone())
2686            }
2687            (FloatClass::NegativeZero, FloatClass::NegativeZero) => {
2688                Self::negative_zero_with_traits(self.traits.clone())
2689            }
2690            _ => {
2691                let lhs_value = self.to_real_algebraic_number().expect("known to be finite");
2692                let rhs_value = rhs.to_real_algebraic_number().expect("known to be finite");
2693                let result = if is_sub {
2694                    lhs_value - rhs_value
2695                } else {
2696                    lhs_value + rhs_value
2697                };
2698                if result.is_zero() {
2699                    match rounding_mode {
2700                        RoundingMode::TiesToEven
2701                        | RoundingMode::TiesToAway
2702                        | RoundingMode::TowardPositive
2703                        | RoundingMode::TowardZero => {
2704                            Self::positive_zero_with_traits(self.traits.clone())
2705                        }
2706                        RoundingMode::TowardNegative => {
2707                            Self::negative_zero_with_traits(self.traits.clone())
2708                        }
2709                    }
2710                } else {
2711                    Self::from_real_algebraic_number_with_traits(
2712                        &result,
2713                        Some(rounding_mode),
2714                        Some(fp_state),
2715                        self.traits.clone(),
2716                    )
2717                }
2718            }
2719        }
2720    }
2721    /// add floating-point numbers
2722    pub fn add(
2723        &self,
2724        rhs: &Self,
2725        rounding_mode: Option<RoundingMode>,
2726        fp_state: Option<&mut FPState>,
2727    ) -> Self {
2728        self.add_or_sub(rhs, rounding_mode, fp_state, false)
2729    }
2730    /// subtract floating-point numbers
2731    pub fn sub(
2732        &self,
2733        rhs: &Self,
2734        rounding_mode: Option<RoundingMode>,
2735        fp_state: Option<&mut FPState>,
2736    ) -> Self {
2737        self.add_or_sub(rhs, rounding_mode, fp_state, true)
2738    }
2739    /// multiply floating-point numbers
2740    pub fn mul(
2741        &self,
2742        rhs: &Self,
2743        rounding_mode: Option<RoundingMode>,
2744        fp_state: Option<&mut FPState>,
2745    ) -> Self {
2746        assert_eq!(self.traits, rhs.traits);
2747        let properties = self.properties();
2748        let mut default_fp_state = FPState::default();
2749        let fp_state = fp_state.unwrap_or(&mut default_fp_state);
2750        let rounding_mode = rounding_mode.unwrap_or(fp_state.rounding_mode);
2751        let self_class = self.class();
2752        let rhs_class = rhs.class();
2753        let result_sign = self.sign() * rhs.sign();
2754        if self_class.is_nan() || rhs_class.is_nan() {
2755            if self_class.is_signaling_nan() || rhs_class.is_signaling_nan() {
2756                fp_state.status_flags |= StatusFlags::INVALID_OPERATION;
2757            }
2758            match properties
2759                .platform_properties
2760                .std_bin_ops_nan_propagation_mode
2761                .calculate_propagation_results(self_class, rhs_class)
2762            {
2763                BinaryNaNPropagationResults::First => self.to_quiet_nan(),
2764                BinaryNaNPropagationResults::Second => rhs.to_quiet_nan(),
2765                BinaryNaNPropagationResults::Canonical => {
2766                    Self::quiet_nan_with_traits(self.traits.clone())
2767                }
2768            }
2769        } else if (self_class.is_infinity() && rhs_class.is_zero())
2770            || (self_class.is_zero() && rhs_class.is_infinity())
2771        {
2772            fp_state.status_flags |= StatusFlags::INVALID_OPERATION;
2773            Self::quiet_nan_with_traits(self.traits.clone())
2774        } else if self_class.is_zero() || rhs_class.is_zero() {
2775            Self::signed_zero_with_traits(result_sign, self.traits.clone())
2776        } else if self_class.is_infinity() || rhs_class.is_infinity() {
2777            Self::signed_infinity_with_traits(result_sign, self.traits.clone())
2778        } else {
2779            let lhs_value = self.to_real_algebraic_number().expect("known to be finite");
2780            let rhs_value = rhs.to_real_algebraic_number().expect("known to be finite");
2781            Self::from_real_algebraic_number_with_traits(
2782                &(lhs_value * rhs_value),
2783                Some(rounding_mode),
2784                Some(fp_state),
2785                self.traits.clone(),
2786            )
2787        }
2788    }
2789    /// divide floating-point numbers
2790    pub fn div(
2791        &self,
2792        rhs: &Self,
2793        rounding_mode: Option<RoundingMode>,
2794        fp_state: Option<&mut FPState>,
2795    ) -> Self {
2796        assert_eq!(self.traits, rhs.traits);
2797        let properties = self.properties();
2798        let mut default_fp_state = FPState::default();
2799        let fp_state = fp_state.unwrap_or(&mut default_fp_state);
2800        let rounding_mode = rounding_mode.unwrap_or(fp_state.rounding_mode);
2801        let self_class = self.class();
2802        let rhs_class = rhs.class();
2803        let result_sign = self.sign() * rhs.sign();
2804        if self_class.is_nan() || rhs_class.is_nan() {
2805            if self_class.is_signaling_nan() || rhs_class.is_signaling_nan() {
2806                fp_state.status_flags |= StatusFlags::INVALID_OPERATION;
2807            }
2808            match properties
2809                .platform_properties
2810                .std_bin_ops_nan_propagation_mode
2811                .calculate_propagation_results(self_class, rhs_class)
2812            {
2813                BinaryNaNPropagationResults::First => self.to_quiet_nan(),
2814                BinaryNaNPropagationResults::Second => rhs.to_quiet_nan(),
2815                BinaryNaNPropagationResults::Canonical => {
2816                    Self::quiet_nan_with_traits(self.traits.clone())
2817                }
2818            }
2819        } else if (self_class.is_infinity() && rhs_class.is_infinity())
2820            || (self_class.is_zero() && rhs_class.is_zero())
2821        {
2822            fp_state.status_flags |= StatusFlags::INVALID_OPERATION;
2823            Self::quiet_nan_with_traits(self.traits.clone())
2824        } else if self_class.is_zero() || rhs_class.is_infinity() {
2825            Self::signed_zero_with_traits(result_sign, self.traits.clone())
2826        } else if self_class.is_infinity() {
2827            Self::signed_infinity_with_traits(result_sign, self.traits.clone())
2828        } else if rhs_class.is_zero() {
2829            fp_state.status_flags |= StatusFlags::DIVISION_BY_ZERO;
2830            Self::signed_infinity_with_traits(result_sign, self.traits.clone())
2831        } else {
2832            let lhs_value = self.to_real_algebraic_number().expect("known to be finite");
2833            let rhs_value = rhs.to_real_algebraic_number().expect("known to be finite");
2834            Self::from_real_algebraic_number_with_traits(
2835                &(lhs_value / rhs_value),
2836                Some(rounding_mode),
2837                Some(fp_state),
2838                self.traits.clone(),
2839            )
2840        }
2841    }
2842    /// compute the IEEE 754 remainder of two floating-point numbers
2843    pub fn ieee754_remainder(
2844        &self,
2845        rhs: &Self,
2846        rounding_mode: Option<RoundingMode>,
2847        fp_state: Option<&mut FPState>,
2848    ) -> Self {
2849        assert_eq!(self.traits, rhs.traits);
2850        let properties = self.properties();
2851        let mut default_fp_state = FPState::default();
2852        let fp_state = fp_state.unwrap_or(&mut default_fp_state);
2853        let rounding_mode = rounding_mode.unwrap_or(fp_state.rounding_mode);
2854        let self_class = self.class();
2855        let rhs_class = rhs.class();
2856        if self_class.is_nan() || rhs_class.is_nan() {
2857            if self_class.is_signaling_nan() || rhs_class.is_signaling_nan() {
2858                fp_state.status_flags |= StatusFlags::INVALID_OPERATION;
2859            }
2860            match properties
2861                .platform_properties
2862                .std_bin_ops_nan_propagation_mode
2863                .calculate_propagation_results(self_class, rhs_class)
2864            {
2865                BinaryNaNPropagationResults::First => self.to_quiet_nan(),
2866                BinaryNaNPropagationResults::Second => rhs.to_quiet_nan(),
2867                BinaryNaNPropagationResults::Canonical => {
2868                    Self::quiet_nan_with_traits(self.traits.clone())
2869                }
2870            }
2871        } else if self_class.is_infinity() || rhs_class.is_zero() {
2872            fp_state.status_flags |= StatusFlags::INVALID_OPERATION;
2873            Self::quiet_nan_with_traits(self.traits.clone())
2874        } else if rhs_class.is_infinity() {
2875            if self_class.is_zero() {
2876                Self::signed_zero_with_traits(self.sign(), self.traits.clone())
2877            } else {
2878                Self::from_real_algebraic_number_with_traits(
2879                    &self.to_real_algebraic_number().expect("known to be finite"),
2880                    Some(rounding_mode),
2881                    Some(fp_state),
2882                    self.traits.clone(),
2883                )
2884            }
2885        } else {
2886            let lhs_value = self.to_real_algebraic_number().expect("known to be finite");
2887            let rhs_value = rhs.to_real_algebraic_number().expect("known to be finite");
2888            let quotient = &lhs_value / &rhs_value;
2889            let floor_quotient = quotient.to_integer_floor();
2890            let fract_quotient = quotient - RealAlgebraicNumber::from(floor_quotient.clone());
2891            let selected_quotient = match fract_quotient.cmp(&Ratio::new(1, 2).into()) {
2892                Ordering::Less => floor_quotient,
2893                Ordering::Greater => floor_quotient + 1,
2894                Ordering::Equal => {
2895                    if floor_quotient.is_even() {
2896                        floor_quotient
2897                    } else {
2898                        floor_quotient + 1
2899                    }
2900                }
2901            };
2902            let remainder = lhs_value - rhs_value * RealAlgebraicNumber::from(selected_quotient);
2903            if remainder.is_zero() {
2904                Self::signed_zero_with_traits(self.sign(), self.traits.clone())
2905            } else {
2906                Self::from_real_algebraic_number_with_traits(
2907                    &remainder,
2908                    Some(rounding_mode),
2909                    Some(fp_state),
2910                    self.traits.clone(),
2911                )
2912            }
2913        }
2914    }
2915    /// calculate the result of `(self * factor) + term` rounding only once, returning the result
2916    pub fn fused_mul_add(
2917        &self,
2918        factor: &Self,
2919        term: &Self,
2920        rounding_mode: Option<RoundingMode>,
2921        fp_state: Option<&mut FPState>,
2922    ) -> Self {
2923        assert_eq!(self.traits, factor.traits);
2924        assert_eq!(self.traits, term.traits);
2925        let properties = self.properties();
2926        let mut default_fp_state = FPState::default();
2927        let fp_state = fp_state.unwrap_or(&mut default_fp_state);
2928        let rounding_mode = rounding_mode.unwrap_or(fp_state.rounding_mode);
2929        let self_class = self.class();
2930        let factor_class = factor.class();
2931        let term_class = term.class();
2932        let product_sign = self.sign() * factor.sign();
2933        let is_infinity_times_zero = (self_class.is_infinity() && factor_class.is_zero())
2934            || (self_class.is_zero() && factor_class.is_infinity());
2935        if self_class.is_nan() || factor_class.is_nan() || term_class.is_nan() {
2936            if self_class.is_signaling_nan()
2937                || factor_class.is_signaling_nan()
2938                || term_class.is_signaling_nan()
2939            {
2940                fp_state.status_flags |= StatusFlags::INVALID_OPERATION;
2941            }
2942            if is_infinity_times_zero && term_class.is_quiet_nan() {
2943                match properties.platform_properties.fma_inf_zero_qnan_result {
2944                    FMAInfZeroQNaNResult::CanonicalAndGenerateInvalid => {
2945                        fp_state.status_flags |= StatusFlags::INVALID_OPERATION;
2946                        return Self::quiet_nan_with_traits(self.traits.clone());
2947                    }
2948                    FMAInfZeroQNaNResult::PropagateAndGenerateInvalid => {
2949                        fp_state.status_flags |= StatusFlags::INVALID_OPERATION;
2950                        return term.clone();
2951                    }
2952                    FMAInfZeroQNaNResult::FollowNaNPropagationMode => {}
2953                }
2954            }
2955            match properties
2956                .platform_properties
2957                .fma_nan_propagation_mode
2958                .calculate_propagation_results(self_class, factor_class, term_class)
2959            {
2960                TernaryNaNPropagationResults::First => self.to_quiet_nan(),
2961                TernaryNaNPropagationResults::Second => factor.to_quiet_nan(),
2962                TernaryNaNPropagationResults::Third => term.to_quiet_nan(),
2963                TernaryNaNPropagationResults::Canonical => {
2964                    Self::quiet_nan_with_traits(self.traits.clone())
2965                }
2966            }
2967        } else if is_infinity_times_zero
2968            || ((self_class.is_infinity() || factor_class.is_infinity())
2969                && term_class.is_infinity()
2970                && product_sign != term.sign())
2971        {
2972            fp_state.status_flags |= StatusFlags::INVALID_OPERATION;
2973            Self::quiet_nan_with_traits(self.traits.clone())
2974        } else if (self_class.is_zero() || factor_class.is_zero())
2975            && term_class.is_zero()
2976            && product_sign == term.sign()
2977        {
2978            Self::signed_zero_with_traits(product_sign, self.traits.clone())
2979        } else if term_class.is_infinity() {
2980            Self::signed_infinity_with_traits(term.sign(), self.traits.clone())
2981        } else if self_class.is_infinity() || factor_class.is_infinity() {
2982            Self::signed_infinity_with_traits(product_sign, self.traits.clone())
2983        } else {
2984            let self_value = self.to_real_algebraic_number().expect("known to be finite");
2985            let factor_value = factor
2986                .to_real_algebraic_number()
2987                .expect("known to be finite");
2988            let term_value = term.to_real_algebraic_number().expect("known to be finite");
2989            let result = self_value * factor_value + term_value;
2990            if result.is_zero() {
2991                match rounding_mode {
2992                    RoundingMode::TiesToEven
2993                    | RoundingMode::TiesToAway
2994                    | RoundingMode::TowardPositive
2995                    | RoundingMode::TowardZero => {
2996                        Self::positive_zero_with_traits(self.traits.clone())
2997                    }
2998                    RoundingMode::TowardNegative => {
2999                        Self::negative_zero_with_traits(self.traits.clone())
3000                    }
3001                }
3002            } else {
3003                Self::from_real_algebraic_number_with_traits(
3004                    &result,
3005                    Some(rounding_mode),
3006                    Some(fp_state),
3007                    self.traits.clone(),
3008                )
3009            }
3010        }
3011    }
3012    /// round `self` to an integer, returning the result as an integer or `None`
3013    pub fn round_to_integer(
3014        &self,
3015        exact: bool,
3016        rounding_mode: Option<RoundingMode>,
3017        fp_state: Option<&mut FPState>,
3018    ) -> Option<BigInt> {
3019        let mut default_fp_state = FPState::default();
3020        let fp_state = fp_state.unwrap_or(&mut default_fp_state);
3021        let rounding_mode = rounding_mode.unwrap_or(fp_state.rounding_mode);
3022        match self.class() {
3023            FloatClass::SignalingNaN => {
3024                fp_state.status_flags |= StatusFlags::INVALID_OPERATION;
3025                return None;
3026            }
3027            class if !class.is_finite() => {
3028                return None;
3029            }
3030            _ => {}
3031        }
3032        let value = self.to_real_algebraic_number().expect("known to be finite");
3033        let lower_value = value.to_integer_floor();
3034        let remainder = value - RealAlgebraicNumber::from(lower_value.clone());
3035        if remainder.is_zero() {
3036            return Some(lower_value);
3037        }
3038        if exact {
3039            fp_state.status_flags |= StatusFlags::INEXACT;
3040        }
3041        let upper_value = &lower_value + 1;
3042        match rounding_mode {
3043            RoundingMode::TiesToAway | RoundingMode::TiesToEven => {
3044                match remainder.cmp(&Ratio::new(1, 2).into()) {
3045                    Ordering::Less => Some(lower_value),
3046                    Ordering::Equal => {
3047                        if rounding_mode == RoundingMode::TiesToEven {
3048                            if lower_value.is_even() {
3049                                Some(lower_value)
3050                            } else {
3051                                Some(upper_value)
3052                            }
3053                        } else {
3054                            assert_eq!(rounding_mode, RoundingMode::TiesToAway);
3055                            if lower_value.is_negative() {
3056                                Some(lower_value)
3057                            } else {
3058                                Some(upper_value)
3059                            }
3060                        }
3061                    }
3062                    Ordering::Greater => Some(upper_value),
3063                }
3064            }
3065            RoundingMode::TowardPositive => Some(upper_value),
3066            RoundingMode::TowardNegative => Some(lower_value),
3067            RoundingMode::TowardZero => {
3068                if lower_value.is_negative() {
3069                    Some(upper_value)
3070                } else {
3071                    Some(lower_value)
3072                }
3073            }
3074        }
3075    }
3076    /// round `self` to an integer, returning the result as a `Float`
3077    pub fn round_to_integral(
3078        &self,
3079        exact: bool,
3080        rounding_mode: Option<RoundingMode>,
3081        fp_state: Option<&mut FPState>,
3082    ) -> Self {
3083        let properties = self.properties();
3084        let mut default_fp_state = FPState::default();
3085        let fp_state = fp_state.unwrap_or(&mut default_fp_state);
3086        let rounding_mode = rounding_mode.unwrap_or(fp_state.rounding_mode);
3087        let class = self.class();
3088        if class.is_nan() {
3089            if class.is_signaling_nan() {
3090                fp_state.status_flags |= StatusFlags::INVALID_OPERATION;
3091            }
3092            match properties
3093                .platform_properties()
3094                .round_to_integral_nan_propagation_mode
3095                .calculate_propagation_results(class)
3096            {
3097                UnaryNaNPropagationResults::Canonical => {
3098                    Self::quiet_nan_with_traits(self.traits.clone())
3099                }
3100                UnaryNaNPropagationResults::First => self.to_quiet_nan(),
3101            }
3102        } else if class.is_infinity() {
3103            Self::signed_infinity_with_traits(self.sign(), self.traits.clone())
3104        } else {
3105            let value = self
3106                .round_to_integer(exact, Some(rounding_mode), Some(fp_state))
3107                .expect("known to be finite");
3108            if value.is_zero() {
3109                Self::signed_zero_with_traits(self.sign(), self.traits.clone())
3110            } else {
3111                Self::from_real_algebraic_number_with_traits(
3112                    &value.into(),
3113                    Some(rounding_mode),
3114                    Some(fp_state),
3115                    self.traits.clone(),
3116                )
3117            }
3118        }
3119    }
3120    /// normalize `self`.
3121    /// This is a no-op for all floating-point formats where
3122    /// `has_implicit_leading_bit` is `true` (which includes all standard
3123    /// floating-point formats).
3124    pub fn normalize(&mut self) {
3125        let properties = self.properties();
3126        if properties.has_implicit_leading_bit() {
3127            return;
3128        }
3129        let mut exponent_field = self.exponent_field();
3130        let exponent_zero_subnormal = properties.exponent_zero_subnormal();
3131        if exponent_field == properties.exponent_inf_nan()
3132            || exponent_field == exponent_zero_subnormal
3133        {
3134            return;
3135        }
3136        let mut mantissa_field = self.mantissa_field();
3137        if mantissa_field.is_zero() {
3138            self.set_exponent_field(exponent_zero_subnormal);
3139            return;
3140        }
3141        let mantissa_field_msb = Bits::one() << properties.fraction_width();
3142        while (mantissa_field.clone() & &mantissa_field_msb).is_zero() {
3143            if exponent_field == exponent_zero_subnormal {
3144                break;
3145            }
3146            exponent_field -= Bits::one();
3147            mantissa_field <<= 1;
3148        }
3149        self.set_exponent_field(exponent_field);
3150        self.set_mantissa_field(mantissa_field);
3151    }
3152    /// compute the result of `next_up` or `next_down`
3153    pub fn next_up_or_down(&self, up_or_down: UpOrDown, fp_state: Option<&mut FPState>) -> Self {
3154        let properties = self.properties();
3155        let mut default_fp_state = FPState::default();
3156        let fp_state = fp_state.unwrap_or(&mut default_fp_state);
3157        match (self.class(), up_or_down) {
3158            (class, _) if class.is_nan() => {
3159                if class.is_signaling_nan() {
3160                    fp_state.status_flags |= StatusFlags::INVALID_OPERATION;
3161                }
3162                match properties
3163                    .platform_properties()
3164                    .next_up_or_down_nan_propagation_mode
3165                    .calculate_propagation_results(class)
3166                {
3167                    UnaryNaNPropagationResults::Canonical => {
3168                        Self::quiet_nan_with_traits(self.traits.clone())
3169                    }
3170                    UnaryNaNPropagationResults::First => self.to_quiet_nan(),
3171                }
3172            }
3173            (FloatClass::NegativeInfinity, UpOrDown::Up)
3174            | (FloatClass::PositiveInfinity, UpOrDown::Down) => {
3175                Self::signed_max_normal_with_traits(self.sign(), self.traits.clone())
3176            }
3177            (FloatClass::NegativeInfinity, UpOrDown::Down)
3178            | (FloatClass::PositiveInfinity, UpOrDown::Up) => self.clone(),
3179            (class, _) if class.is_zero() => {
3180                Self::signed_min_subnormal_with_traits(up_or_down.into(), self.traits.clone())
3181            }
3182            _ => {
3183                let mut retval = self.clone();
3184                retval.normalize();
3185                let mantissa = self.mantissa_field();
3186                let is_larger_magnitude = Sign::from(up_or_down) == self.sign();
3187                if is_larger_magnitude {
3188                    if mantissa == properties.mantissa_field_max() {
3189                        let exponent = self.exponent_field();
3190                        if exponent == properties.exponent_max_normal() {
3191                            Self::signed_infinity_with_traits(self.sign(), self.traits.clone())
3192                        } else {
3193                            let mut retval = self.clone();
3194                            retval.set_mantissa_field(properties.mantissa_field_normal_min());
3195                            retval.set_exponent_field(exponent + Bits::one());
3196                            retval
3197                        }
3198                    } else {
3199                        let mut retval = self.clone();
3200                        retval.set_mantissa_field(mantissa + Bits::one());
3201                        retval
3202                    }
3203                } else if mantissa <= properties.mantissa_field_normal_min() {
3204                    let exponent = self.exponent_field();
3205                    if exponent == properties.exponent_zero_subnormal() {
3206                        assert!(!mantissa.is_zero());
3207                        let mut retval = self.clone();
3208                        retval.set_mantissa_field(mantissa - Bits::one());
3209                        retval
3210                    } else {
3211                        let mut retval = self.clone();
3212                        retval.set_mantissa_field(properties.mantissa_field_max());
3213                        retval.set_exponent_field(exponent - Bits::one());
3214                        retval
3215                    }
3216                } else {
3217                    let mut retval = self.clone();
3218                    retval.set_mantissa_field(mantissa - Bits::one());
3219                    retval
3220                }
3221            }
3222        }
3223    }
3224    /// compute the least floating-point number that compares greater than `self`
3225    pub fn next_up(&self, fp_state: Option<&mut FPState>) -> Self {
3226        self.next_up_or_down(UpOrDown::Up, fp_state)
3227    }
3228    /// compute the greatest floating-point number that compares less than `self`
3229    pub fn next_down(&self, fp_state: Option<&mut FPState>) -> Self {
3230        self.next_up_or_down(UpOrDown::Down, fp_state)
3231    }
3232    /// get the floor of the log base 2 of the absolute value of `self`
3233    pub fn log_b(&self, fp_state: Option<&mut FPState>) -> Option<BigInt> {
3234        let mut default_fp_state = FPState::default();
3235        let fp_state = fp_state.unwrap_or(&mut default_fp_state);
3236        let properties = self.properties();
3237        let class = self.class();
3238        if !class.is_finite() || class.is_zero() {
3239            fp_state.status_flags |= StatusFlags::INVALID_OPERATION;
3240            return None;
3241        }
3242        let exponent_field: BigInt = self.exponent_field().into();
3243        let exponent_bias: BigInt = properties.exponent_bias::<Bits>().into();
3244        let exponent_zero_subnormal: BigInt = properties.exponent_zero_subnormal::<Bits>().into();
3245        let mut exponent =
3246            if properties.has_implicit_leading_bit() && exponent_field != exponent_zero_subnormal {
3247                return Some(exponent_field - exponent_bias);
3248            } else if exponent_field == exponent_zero_subnormal {
3249                properties.exponent_min_normal::<Bits>().into() - exponent_bias
3250            } else {
3251                exponent_field - exponent_bias
3252            };
3253        let mut mantissa = self.mantissa_field();
3254        while (mantissa.clone() >> properties.fraction_width()).is_zero() {
3255            mantissa <<= 1;
3256            exponent -= 1;
3257        }
3258        Some(exponent)
3259    }
3260    /// get `self * 2^scale`
3261    pub fn scale_b(
3262        &self,
3263        mut scale: BigInt,
3264        rounding_mode: Option<RoundingMode>,
3265        fp_state: Option<&mut FPState>,
3266    ) -> Self {
3267        let mut default_fp_state = FPState::default();
3268        let fp_state = fp_state.unwrap_or(&mut default_fp_state);
3269        let rounding_mode = rounding_mode.unwrap_or(fp_state.rounding_mode);
3270        let properties = self.properties();
3271        let class = self.class();
3272        if class.is_nan() {
3273            if class.is_signaling_nan() {
3274                fp_state.status_flags |= StatusFlags::INVALID_OPERATION;
3275            }
3276            match properties
3277                .platform_properties()
3278                .scale_b_nan_propagation_mode
3279                .calculate_propagation_results(class)
3280            {
3281                UnaryNaNPropagationResults::Canonical => {
3282                    Self::quiet_nan_with_traits(self.traits.clone())
3283                }
3284                UnaryNaNPropagationResults::First => self.to_quiet_nan(),
3285            }
3286        } else if class.is_infinity() {
3287            Self::signed_infinity_with_traits(self.sign(), self.traits.clone())
3288        } else if class.is_zero() {
3289            Self::signed_zero_with_traits(self.sign(), self.traits.clone())
3290        } else {
3291            let exponent_max_normal: BigInt = properties.exponent_max_normal::<Bits>().into();
3292            let exponent_min_normal: BigInt = properties.exponent_min_normal::<Bits>().into();
3293            let scale_limit: BigInt =
3294                (exponent_max_normal - exponent_min_normal + properties.fraction_width() + 1) * 2;
3295            scale = scale.max(-&scale_limit);
3296            scale = scale.min(scale_limit);
3297            let mut value = self.to_real_algebraic_number().expect("known to be finite");
3298            if scale.is_positive() {
3299                value *= RealAlgebraicNumber::from(
3300                    BigInt::one() << scale.to_usize().expect("rhs won't fit in usize"),
3301                );
3302            } else {
3303                value /= RealAlgebraicNumber::from(
3304                    BigInt::one() << (-scale).to_usize().expect("-rhs won't fit in usize"),
3305                );
3306            }
3307            Self::from_real_algebraic_number_with_traits(
3308                &value,
3309                Some(rounding_mode),
3310                Some(fp_state),
3311                self.traits.clone(),
3312            )
3313        }
3314    }
3315    /// get the square-root of `self`
3316    pub fn sqrt(
3317        &self,
3318        rounding_mode: Option<RoundingMode>,
3319        fp_state: Option<&mut FPState>,
3320    ) -> Self {
3321        let properties = self.properties();
3322        let mut default_fp_state = FPState::default();
3323        let fp_state = fp_state.unwrap_or(&mut default_fp_state);
3324        let rounding_mode = rounding_mode.unwrap_or(fp_state.rounding_mode);
3325        let class = self.class();
3326        if class.is_nan() {
3327            if class.is_signaling_nan() {
3328                fp_state.status_flags |= StatusFlags::INVALID_OPERATION;
3329            }
3330            match properties
3331                .platform_properties()
3332                .sqrt_nan_propagation_mode
3333                .calculate_propagation_results(class)
3334            {
3335                UnaryNaNPropagationResults::Canonical => {
3336                    Self::quiet_nan_with_traits(self.traits.clone())
3337                }
3338                UnaryNaNPropagationResults::First => self.to_quiet_nan(),
3339            }
3340        } else if class.is_zero() {
3341            Self::signed_zero_with_traits(self.sign(), self.traits.clone())
3342        } else if class.is_positive_infinity() {
3343            Self::positive_infinity_with_traits(self.traits.clone())
3344        } else if self.sign() == Sign::Negative {
3345            fp_state.status_flags |= StatusFlags::INVALID_OPERATION;
3346            Self::quiet_nan_with_traits(self.traits.clone())
3347        } else {
3348            let value = self.to_real_algebraic_number().expect("known to be finite");
3349            Self::from_real_algebraic_number_with_traits(
3350                &value.pow((1, 2)),
3351                Some(rounding_mode),
3352                Some(fp_state),
3353                self.traits.clone(),
3354            )
3355        }
3356    }
3357    /// convert `src` to the floating-point format specified by `traits`.
3358    pub fn convert_from_float_with_traits<SrcFT: FloatTraits>(
3359        src: &Float<SrcFT>,
3360        rounding_mode: Option<RoundingMode>,
3361        fp_state: Option<&mut FPState>,
3362        traits: FT,
3363    ) -> Self {
3364        let src_properties = src.properties();
3365        let dest_properties = traits.properties();
3366        let mut default_fp_state = FPState::default();
3367        let fp_state = fp_state.unwrap_or(&mut default_fp_state);
3368        let rounding_mode = rounding_mode.unwrap_or(fp_state.rounding_mode);
3369        let class = src.class();
3370        if class.is_nan() {
3371            if class.is_signaling_nan() {
3372                fp_state.status_flags |= StatusFlags::INVALID_OPERATION;
3373            }
3374            let mut retval = Self::quiet_nan_with_traits(traits);
3375            match dest_properties
3376                .platform_properties
3377                .float_to_float_conversion_nan_propagation_mode
3378            {
3379                FloatToFloatConversionNaNPropagationMode::AlwaysCanonical => retval,
3380                FloatToFloatConversionNaNPropagationMode::RetainMostSignificantBits => {
3381                    let mut mantissa: BigInt = src.mantissa_field().into();
3382                    let retained_bits = src_properties
3383                        .mantissa_width()
3384                        .min(dest_properties.mantissa_width());
3385                    mantissa >>= src_properties.mantissa_width() - retained_bits;
3386                    mantissa <<= dest_properties.mantissa_width() - retained_bits;
3387                    retval.set_mantissa_field(
3388                        Bits::from_bigint(&mantissa).expect("mantissa doesn't fit"),
3389                    );
3390                    retval.to_quiet_nan()
3391                }
3392            }
3393        } else if class.is_infinity() {
3394            Self::signed_infinity_with_traits(src.sign(), traits)
3395        } else if class.is_zero() {
3396            Self::signed_zero_with_traits(src.sign(), traits)
3397        } else {
3398            let value = src.to_real_algebraic_number().expect("known to be finite");
3399            Self::from_real_algebraic_number_with_traits(
3400                &value,
3401                Some(rounding_mode),
3402                Some(fp_state),
3403                traits,
3404            )
3405        }
3406    }
3407    /// convert `src` to the floating-point format specified by `FT::default()` where `Self` is `Float<FT>`.
3408    pub fn convert_from_float<SrcFT: FloatTraits>(
3409        src: &Float<SrcFT>,
3410        rounding_mode: Option<RoundingMode>,
3411        fp_state: Option<&mut FPState>,
3412    ) -> Self
3413    where
3414        FT: Default,
3415    {
3416        Self::convert_from_float_with_traits(src, rounding_mode, fp_state, FT::default())
3417    }
3418    /// convert `self` to the floating-point format specified by `traits`.
3419    pub fn convert_to_float_with_traits<DestFT: FloatTraits>(
3420        &self,
3421        rounding_mode: Option<RoundingMode>,
3422        fp_state: Option<&mut FPState>,
3423        traits: DestFT,
3424    ) -> Float<DestFT> {
3425        Float::convert_from_float_with_traits(self, rounding_mode, fp_state, traits)
3426    }
3427    /// convert `self` to the floating-point format specified by `DestFT::default()`.
3428    pub fn convert_to_float<DestFT: FloatTraits + Default>(
3429        &self,
3430        rounding_mode: Option<RoundingMode>,
3431        fp_state: Option<&mut FPState>,
3432    ) -> Float<DestFT> {
3433        Float::convert_from_float(self, rounding_mode, fp_state)
3434    }
3435    /// negate and assign the result back to `self`.
3436    /// identical to `self.toggle_sign()`
3437    pub fn neg_assign(&mut self) {
3438        self.toggle_sign();
3439    }
3440    /// compute the negation of `self`
3441    pub fn neg(&self) -> Self {
3442        let mut retval = self.clone();
3443        retval.neg_assign();
3444        retval
3445    }
3446    /// compute the absolute-value and assign the result back to `self`.
3447    /// identical to `self.set_sign(Sign::Positive)`
3448    pub fn abs_assign(&mut self) {
3449        self.set_sign(Sign::Positive);
3450    }
3451    /// compute the absolute-value
3452    pub fn abs(&self) -> Self {
3453        let mut retval = self.clone();
3454        retval.abs_assign();
3455        retval
3456    }
3457    /// set `self`'s sign to the sign of `sign_src`
3458    pub fn copy_sign_assign<FT2: FloatTraits>(&mut self, sign_src: &Float<FT2>) {
3459        self.set_sign(sign_src.sign());
3460    }
3461    /// construct a `Float` from `self` but with the sign of `sign_src`
3462    pub fn copy_sign<FT2: FloatTraits>(&self, sign_src: &Float<FT2>) -> Self {
3463        let mut retval = self.clone();
3464        retval.set_sign(sign_src.sign());
3465        retval
3466    }
3467    /// compare two `Float` values
3468    pub fn compare(
3469        &self,
3470        rhs: &Self,
3471        quiet: bool,
3472        fp_state: Option<&mut FPState>,
3473    ) -> Option<Ordering> {
3474        let self_class = self.class();
3475        let rhs_class = rhs.class();
3476        if self_class.is_nan() || rhs_class.is_nan() {
3477            if !quiet || self_class.is_signaling_nan() || rhs_class.is_signaling_nan() {
3478                if let Some(fp_state) = fp_state {
3479                    fp_state.status_flags |= StatusFlags::INVALID_OPERATION;
3480                }
3481            }
3482            None
3483        } else if self_class.is_infinity() || rhs_class.is_infinity() {
3484            if self_class == rhs_class {
3485                Some(Ordering::Equal)
3486            } else if self_class.is_positive_infinity() || rhs_class.is_negative_infinity() {
3487                Some(Ordering::Greater)
3488            } else {
3489                Some(Ordering::Less)
3490            }
3491        } else {
3492            Some(
3493                self.to_ratio()
3494                    .expect("known to be finite")
3495                    .cmp(&rhs.to_ratio().expect("known to be finite")),
3496            )
3497        }
3498    }
3499    /// compare two `Float` values
3500    pub fn compare_quiet(&self, rhs: &Self, fp_state: Option<&mut FPState>) -> Option<Ordering> {
3501        self.compare(rhs, true, fp_state)
3502    }
3503    /// compare two `Float` values
3504    pub fn compare_signaling(
3505        &self,
3506        rhs: &Self,
3507        fp_state: Option<&mut FPState>,
3508    ) -> Option<Ordering> {
3509        self.compare(rhs, false, fp_state)
3510    }
3511    impl_from_int_type!(from_bigint_with_traits, from_bigint, BigInt);
3512    impl_from_int_type!(from_biguint_with_traits, from_biguint, BigUint);
3513    impl_from_int_type!(from_u8_with_traits, from_u8, u8);
3514    impl_from_int_type!(from_u16_with_traits, from_u16, u16);
3515    impl_from_int_type!(from_u32_with_traits, from_u32, u32);
3516    impl_from_int_type!(from_u64_with_traits, from_u64, u64);
3517    impl_from_int_type!(from_u128_with_traits, from_u128, u128);
3518    impl_from_int_type!(from_usize_with_traits, from_usize, usize);
3519    impl_from_int_type!(from_i8_with_traits, from_i8, i8);
3520    impl_from_int_type!(from_i16_with_traits, from_i16, i16);
3521    impl_from_int_type!(from_i32_with_traits, from_i32, i32);
3522    impl_from_int_type!(from_i64_with_traits, from_i64, i64);
3523    impl_from_int_type!(from_i128_with_traits, from_i128, i128);
3524    impl_from_int_type!(from_isize_with_traits, from_isize, isize);
3525    impl_to_int_type!(to_bigint, into, BigInt);
3526    impl_to_int_type!(to_biguint, to_biguint, BigUint);
3527    impl_to_int_type!(to_u8, to_u8, u8);
3528    impl_to_int_type!(to_u16, to_u16, u16);
3529    impl_to_int_type!(to_u32, to_u32, u32);
3530    impl_to_int_type!(to_u64, to_u64, u64);
3531    impl_to_int_type!(to_u128, to_u128, u128);
3532    impl_to_int_type!(to_usize, to_usize, usize);
3533    impl_to_int_type!(to_i8, to_i8, i8);
3534    impl_to_int_type!(to_i16, to_i16, i16);
3535    impl_to_int_type!(to_i32, to_i32, i32);
3536    impl_to_int_type!(to_i64, to_i64, i64);
3537    impl_to_int_type!(to_i128, to_i128, i128);
3538    impl_to_int_type!(to_isize, to_isize, isize);
3539    /// reciprocal square root -- computes `1 / sqrt(self)`
3540    pub fn rsqrt(
3541        &self,
3542        rounding_mode: Option<RoundingMode>,
3543        fp_state: Option<&mut FPState>,
3544    ) -> Self {
3545        let properties = self.properties();
3546        let mut default_fp_state = FPState::default();
3547        let fp_state = fp_state.unwrap_or(&mut default_fp_state);
3548        let rounding_mode = rounding_mode.unwrap_or(fp_state.rounding_mode);
3549        let class = self.class();
3550        if class.is_nan() {
3551            if class.is_signaling_nan() {
3552                fp_state.status_flags |= StatusFlags::INVALID_OPERATION;
3553            }
3554            match properties
3555                .platform_properties()
3556                .rsqrt_nan_propagation_mode
3557                .calculate_propagation_results(class)
3558            {
3559                UnaryNaNPropagationResults::Canonical => {
3560                    Self::quiet_nan_with_traits(self.traits.clone())
3561                }
3562                UnaryNaNPropagationResults::First => self.to_quiet_nan(),
3563            }
3564        } else if class.is_zero() {
3565            fp_state.status_flags |= StatusFlags::DIVISION_BY_ZERO;
3566            Self::signed_infinity_with_traits(self.sign(), self.traits.clone())
3567        } else if class.is_positive_infinity() {
3568            Self::positive_zero_with_traits(self.traits.clone())
3569        } else if self.sign() == Sign::Negative {
3570            fp_state.status_flags |= StatusFlags::INVALID_OPERATION;
3571            Self::quiet_nan_with_traits(self.traits.clone())
3572        } else {
3573            let value = self.to_real_algebraic_number().expect("known to be finite");
3574            Self::from_real_algebraic_number_with_traits(
3575                &value.recip().pow((1, 2)),
3576                Some(rounding_mode),
3577                Some(fp_state),
3578                self.traits.clone(),
3579            )
3580        }
3581    }
3582}
3583
3584impl<Bits: FloatBitsType, FT: FloatTraits<Bits = Bits>> fmt::Debug for Float<FT> {
3585    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3586        let properties = self.properties();
3587        let mut debug_struct = f.debug_struct("Float");
3588        debug_struct.field("traits", &self.traits);
3589        debug_struct.field(
3590            "bits",
3591            &format_args!(
3592                "0x{value:0width$X}",
3593                value = self.bits(),
3594                width = (properties.width() + 3) / 4
3595            ),
3596        );
3597        if properties.has_sign_bit() {
3598            debug_struct.field("sign", &self.sign());
3599        }
3600        debug_struct.field(
3601            "exponent_field",
3602            &format_args!(
3603                "0x{value:0width$X}",
3604                value = self.exponent_field(),
3605                width = (properties.exponent_width() + 3) / 4
3606            ),
3607        );
3608        debug_struct.field(
3609            "mantissa_field",
3610            &format_args!(
3611                "0x{value:0width$X}",
3612                value = self.mantissa_field(),
3613                width = (properties.mantissa_width() + 3) / 4
3614            ),
3615        );
3616        debug_struct.field("class", &self.class());
3617        debug_struct.finish()
3618    }
3619}
3620
3621/// standard 16-bit float
3622pub type F16 = Float<F16Traits>;
3623/// standard 32-bit float
3624pub type F32 = Float<F32Traits>;
3625/// standard 64-bit float
3626pub type F64 = Float<F64Traits>;
3627/// standard 128-bit float
3628pub type F128 = Float<F128Traits>;
3629
3630/// standard 16-bit float
3631pub type F16WithPlatformProperties = Float<F16WithPlatformPropertiesTraits>;
3632/// standard 32-bit float
3633pub type F32WithPlatformProperties = Float<F32WithPlatformPropertiesTraits>;
3634/// standard 64-bit float
3635pub type F64WithPlatformProperties = Float<F64WithPlatformPropertiesTraits>;
3636/// standard 128-bit float
3637pub type F128WithPlatformProperties = Float<F128WithPlatformPropertiesTraits>;
3638
3639/// `Float` with attached `FPState` and dynamically settable `FloatProperties`
3640#[derive(Clone, Debug)]
3641pub struct DynamicFloat {
3642    /// floating-point state
3643    pub fp_state: FPState,
3644    /// floating-point value; also accessible through `*self`
3645    pub value: Float<FloatProperties>,
3646    _private: (),
3647}
3648
3649impl Deref for DynamicFloat {
3650    type Target = Float<FloatProperties>;
3651    /// returns `&self.value`
3652    fn deref(&self) -> &Float<FloatProperties> {
3653        &self.value
3654    }
3655}
3656
3657impl DerefMut for DynamicFloat {
3658    /// returns `&mut self.value`
3659    fn deref_mut(&mut self) -> &mut Float<FloatProperties> {
3660        &mut self.value
3661    }
3662}
3663
3664impl From<Float<FloatProperties>> for DynamicFloat {
3665    fn from(value: Float<FloatProperties>) -> Self {
3666        Self {
3667            fp_state: FPState::default(),
3668            value,
3669            _private: (),
3670        }
3671    }
3672}
3673
3674impl From<DynamicFloat> for Float<FloatProperties> {
3675    fn from(value: DynamicFloat) -> Self {
3676        value.value
3677    }
3678}
3679
3680macro_rules! impl_dynamic_float_fn {
3681    (
3682        $(#[doc = $doc:literal])+
3683        $fn_name:ident, $called_fn_name:ident,
3684        (&self$(, $args:ident: $arg_types:ty)*)
3685    ) => {
3686        impl DynamicFloat {
3687            $(#[doc = $doc])+
3688            pub fn $fn_name(
3689                &self,
3690                $($args: $arg_types,)*
3691            ) -> Self {
3692                let mut fp_state = self.fp_state;
3693                let value = self
3694                    .value
3695                    .$called_fn_name($($args,)* Some(&mut fp_state));
3696                Self {
3697                    fp_state,
3698                    value,
3699                    _private: (),
3700                }
3701            }
3702        }
3703    };
3704    (
3705        $(#[doc = $doc:literal])+
3706        $fn_name:ident, $checked_fn_name:ident, $called_fn_name:ident,
3707        (&self$(, $before_args:ident: $before_arg_types:ty)*),
3708        ($($float_args:ident: &Self),*),
3709        ($($after_args:ident: $after_arg_types:ty),*)
3710    ) => {
3711        impl DynamicFloat {
3712            $(#[doc = $doc])+
3713            pub fn $fn_name(
3714                &self,
3715                $($before_args: $before_args_type,)*
3716                $($float_args: &Self,)*
3717                $($after_args: $after_arg_types,)*
3718            ) -> Self {
3719                let mut fp_state = self.fp_state;
3720                $(fp_state.merge_assign($float_args.fp_state);)*
3721                let value = self
3722                    .value
3723                    .$called_fn_name($($before_args,)* $(&$float_args.value,)* $($after_args,)* Some(&mut fp_state));
3724                Self {
3725                    fp_state,
3726                    value,
3727                    _private: (),
3728                }
3729            }
3730            $(#[doc = $doc])+
3731            pub fn $checked_fn_name(
3732                &self,
3733                $($before_args: $before_args_type,)*
3734                $($float_args: &Self,)*
3735                $($after_args: $after_arg_types,)*
3736            ) -> Result<Self, FPStateMergeFailed> {
3737                let mut fp_state = self.fp_state;
3738                $(fp_state.checked_merge_assign($float_args.fp_state)?;)*
3739                let value = self
3740                    .value
3741                    .$called_fn_name($($before_args,)* $(&$float_args.value,)* $($after_args,)* Some(&mut fp_state));
3742                Ok(Self {
3743                    fp_state,
3744                    value,
3745                    _private: (),
3746                })
3747            }
3748        }
3749    };
3750}
3751
3752macro_rules! impl_dynamic_float_from_int_type {
3753    ($from_int_with_traits:ident, $from_int:ident, $int:ident) => {
3754        impl DynamicFloat {
3755            /// convert from integer to floating-point.
3756            /// `rounding_mode` only used for this conversion.
3757            pub fn $from_int(
3758                value: $int,
3759                rounding_mode: Option<RoundingMode>,
3760                fp_state: Option<FPState>,
3761                properties: FloatProperties,
3762            ) -> Self {
3763                let mut fp_state = fp_state.unwrap_or_default();
3764                let value = Float::$from_int_with_traits(
3765                    value,
3766                    rounding_mode,
3767                    Some(&mut fp_state),
3768                    properties,
3769                );
3770                Self {
3771                    fp_state,
3772                    value,
3773                    _private: (),
3774                }
3775            }
3776        }
3777    };
3778}
3779
3780macro_rules! impl_dynamic_float_to_int_type {
3781    ($name:ident, $int:ident) => {
3782        impl DynamicFloat {
3783            /// convert `self` to an integer, returning the result as a tuple of an integer or `None`, and `FPState`
3784            pub fn $name(
3785                &self,
3786                exact: bool,
3787                rounding_mode: Option<RoundingMode>,
3788            ) -> (Option<$int>, FPState) {
3789                let mut fp_state = self.fp_state;
3790                let result = self.value.$name(exact, rounding_mode, Some(&mut fp_state));
3791                (result, fp_state)
3792            }
3793        }
3794    };
3795}
3796
3797impl DynamicFloat {
3798    /// create from `properties`
3799    pub fn new(properties: FloatProperties) -> Self {
3800        Self {
3801            fp_state: FPState::default(),
3802            value: Float::from_bits_and_traits(BigUint::zero(), properties),
3803            _private: (),
3804        }
3805    }
3806    /// create from `bits` and `properties`
3807    pub fn from_bits(bits: BigUint, properties: FloatProperties) -> Option<Self> {
3808        if bits <= properties.overall_mask::<BigUint>() {
3809            Some(Self {
3810                fp_state: FPState::default(),
3811                value: Float::from_bits_and_traits(bits, properties),
3812                _private: (),
3813            })
3814        } else {
3815            None
3816        }
3817    }
3818    /// get the bits of `self`
3819    pub fn into_bits(self) -> BigUint {
3820        self.value.into_bits()
3821    }
3822    /// get the positive zero value
3823    pub fn positive_zero(properties: FloatProperties) -> Self {
3824        Float::positive_zero_with_traits(properties).into()
3825    }
3826    /// get the negative zero value
3827    pub fn negative_zero(properties: FloatProperties) -> Self {
3828        Float::negative_zero_with_traits(properties).into()
3829    }
3830    /// get the zero with sign `sign`
3831    pub fn signed_zero(sign: Sign, properties: FloatProperties) -> Self {
3832        Float::signed_zero_with_traits(sign, properties).into()
3833    }
3834    /// get the positive infinity value
3835    pub fn positive_infinity(properties: FloatProperties) -> Self {
3836        Float::positive_infinity_with_traits(properties).into()
3837    }
3838    /// get the negative infinity value
3839    pub fn negative_infinity(properties: FloatProperties) -> Self {
3840        Float::negative_infinity_with_traits(properties).into()
3841    }
3842    /// get the infinity with sign `sign`
3843    pub fn signed_infinity(sign: Sign, properties: FloatProperties) -> Self {
3844        Float::signed_infinity_with_traits(sign, properties).into()
3845    }
3846    /// get the canonical quiet NaN, which is also just the canonical NaN
3847    pub fn quiet_nan(properties: FloatProperties) -> Self {
3848        Float::quiet_nan_with_traits(properties).into()
3849    }
3850    /// get the canonical signaling NaN
3851    pub fn signaling_nan(properties: FloatProperties) -> Self {
3852        Float::signaling_nan_with_traits(properties).into()
3853    }
3854    /// convert `self` into a quiet NaN
3855    pub fn into_quiet_nan(self) -> Self {
3856        let Self {
3857            fp_state,
3858            value,
3859            _private: _,
3860        } = self;
3861        Self {
3862            fp_state,
3863            value: value.into_quiet_nan(),
3864            _private: (),
3865        }
3866    }
3867    /// convert `self` into a quiet NaN
3868    pub fn to_quiet_nan(&self) -> Self {
3869        let Self {
3870            fp_state,
3871            ref value,
3872            _private: _,
3873        } = *self;
3874        Self {
3875            fp_state,
3876            value: value.to_quiet_nan(),
3877            _private: (),
3878        }
3879    }
3880    /// get the largest finite value with sign `sign`
3881    pub fn signed_max_normal(sign: Sign, properties: FloatProperties) -> Self {
3882        Float::signed_max_normal_with_traits(sign, properties).into()
3883    }
3884    /// get the subnormal value closest to zero with sign `sign`
3885    pub fn signed_min_subnormal(sign: Sign, properties: FloatProperties) -> Self {
3886        Float::signed_min_subnormal_with_traits(sign, properties).into()
3887    }
3888    /// round from a `RealAlgebraicNumber` into a floating-point value.
3889    /// `rounding_mode` only used for this conversion
3890    pub fn from_real_algebraic_number(
3891        value: &RealAlgebraicNumber,
3892        rounding_mode: Option<RoundingMode>,
3893        fp_state: Option<FPState>,
3894        properties: FloatProperties,
3895    ) -> Self {
3896        let mut fp_state = fp_state.unwrap_or_default();
3897        let value = Float::from_real_algebraic_number_with_traits(
3898            value,
3899            rounding_mode,
3900            Some(&mut fp_state),
3901            properties,
3902        );
3903        Self {
3904            fp_state,
3905            value,
3906            _private: (),
3907        }
3908    }
3909}
3910impl_dynamic_float_fn!(
3911    /// add two `DynamicFloat` values, returning the result
3912    add_with_rounding_mode,
3913    checked_add_with_rounding_mode,
3914    add,
3915    (&self),
3916    (rhs: &Self),
3917    (rounding_mode: Option<RoundingMode>)
3918);
3919impl_dynamic_float_fn!(
3920    /// subtract two `DynamicFloat` values, returning the result
3921    sub_with_rounding_mode,
3922    checked_sub_with_rounding_mode,
3923    sub,
3924    (&self),
3925    (rhs: &Self),
3926    (rounding_mode: Option<RoundingMode>)
3927);
3928impl_dynamic_float_fn!(
3929    /// multiply two `DynamicFloat` values, returning the result
3930    mul_with_rounding_mode,
3931    checked_mul_with_rounding_mode,
3932    mul,
3933    (&self),
3934    (rhs: &Self),
3935    (rounding_mode: Option<RoundingMode>)
3936);
3937impl_dynamic_float_fn!(
3938    /// divide two `DynamicFloat` values, returning the result
3939    div_with_rounding_mode,
3940    checked_div_with_rounding_mode,
3941    div,
3942    (&self),
3943    (rhs: &Self),
3944    (rounding_mode: Option<RoundingMode>)
3945);
3946impl_dynamic_float_fn!(
3947    /// calculate the IEEE 754 remainder of two `DynamicFloat` values, returning the result
3948    ieee754_remainder,
3949    checked_ieee754_remainder,
3950    ieee754_remainder,
3951    (&self),
3952    (rhs: &Self),
3953    (rounding_mode: Option<RoundingMode>)
3954);
3955impl_dynamic_float_fn!(
3956    /// calculate the result of `(self * factor) + term` rounding only once, returning the result
3957    fused_mul_add,
3958    checked_fused_mul_add,
3959    fused_mul_add,
3960    (&self),
3961    (factor: &Self, term: &Self),
3962    (rounding_mode: Option<RoundingMode>)
3963);
3964
3965impl DynamicFloat {
3966    /// round `self` to an integer, returning the result as a tuple of an integer or `None`, and `FPState`
3967    pub fn round_to_integer(
3968        &self,
3969        exact: bool,
3970        rounding_mode: Option<RoundingMode>,
3971    ) -> (Option<BigInt>, FPState) {
3972        let mut fp_state = self.fp_state;
3973        let value = self
3974            .value
3975            .round_to_integer(exact, rounding_mode, Some(&mut fp_state));
3976        (value, fp_state)
3977    }
3978}
3979
3980impl_dynamic_float_fn!(
3981    /// round `self` to an integer, returning the result as a `DynamicFloat`
3982    round_to_integral,
3983    round_to_integral,
3984    (&self, exact: bool, rounding_mode: Option<RoundingMode>)
3985);
3986impl_dynamic_float_fn!(
3987    /// compute the result of `next_up` or `next_down`
3988    next_up_or_down,
3989    next_up_or_down,
3990    (&self, up_or_down: UpOrDown)
3991);
3992impl_dynamic_float_fn!(
3993    /// compute the least floating-point number that compares greater than `self`
3994    next_up,
3995    next_up,
3996    (&self)
3997);
3998impl_dynamic_float_fn!(
3999    /// compute the greatest floating-point number that compares less than `self`
4000    next_down,
4001    next_down,
4002    (&self)
4003);
4004
4005impl DynamicFloat {
4006    /// get the floor of the log base 2 of the absolute value of `self`
4007    pub fn log_b(&self) -> (Option<BigInt>, FPState) {
4008        let mut fp_state = self.fp_state;
4009        let value = self.value.log_b(Some(&mut fp_state));
4010        (value, fp_state)
4011    }
4012}
4013
4014impl_dynamic_float_fn!(
4015    /// get `self * 2^scale`
4016    scale_b,
4017    scale_b,
4018    (&self, scale: BigInt, rounding_mode: Option<RoundingMode>)
4019);
4020impl_dynamic_float_fn!(
4021    /// get the square-root of `self`
4022    sqrt,
4023    sqrt,
4024    (&self, rounding_mode: Option<RoundingMode>)
4025);
4026
4027impl DynamicFloat {
4028    /// convert `src` to the floating-point format specified by `properties`.
4029    pub fn convert_from_dynamic_float(
4030        src: &Self,
4031        rounding_mode: Option<RoundingMode>,
4032        properties: FloatProperties,
4033    ) -> Self {
4034        let mut fp_state = src.fp_state;
4035        let value = Float::convert_from_float_with_traits(
4036            &src.value,
4037            rounding_mode,
4038            Some(&mut fp_state),
4039            properties,
4040        );
4041        Self {
4042            fp_state,
4043            value,
4044            _private: (),
4045        }
4046    }
4047    /// convert `src` to the floating-point format specified by `properties`.
4048    pub fn convert_from_float<SrcFT: FloatTraits>(
4049        src: &Float<SrcFT>,
4050        rounding_mode: Option<RoundingMode>,
4051        fp_state: Option<FPState>,
4052        properties: FloatProperties,
4053    ) -> Self {
4054        let mut fp_state = fp_state.unwrap_or_default();
4055        let value = Float::convert_from_float_with_traits(
4056            src,
4057            rounding_mode,
4058            Some(&mut fp_state),
4059            properties,
4060        );
4061        Self {
4062            fp_state,
4063            value,
4064            _private: (),
4065        }
4066    }
4067    /// convert `self` to the floating-point format specified by `properties`.
4068    pub fn convert_to_dynamic_float(
4069        &self,
4070        rounding_mode: Option<RoundingMode>,
4071        properties: FloatProperties,
4072    ) -> Self {
4073        Self::convert_from_dynamic_float(self, rounding_mode, properties)
4074    }
4075    /// compute the absolute value of `self`
4076    pub fn abs(&self) -> Self {
4077        let mut retval = self.clone();
4078        retval.abs_assign();
4079        retval
4080    }
4081    /// construct a `DynamicFloat` from `self` but with the sign of `sign_src`
4082    pub fn copy_sign<FT2: FloatTraits>(&self, sign_src: &Float<FT2>) -> Self {
4083        let mut retval = self.clone();
4084        retval.set_sign(sign_src.sign());
4085        retval
4086    }
4087    /// compare two `DynamicFloat` values
4088    pub fn compare(&self, rhs: &Self, quiet: bool) -> (Option<Ordering>, FPState) {
4089        let mut fp_state = self.fp_state;
4090        fp_state.merge_assign(rhs.fp_state);
4091        let result = self.value.compare(&rhs.value, quiet, Some(&mut fp_state));
4092        (result, fp_state)
4093    }
4094    /// compare two `DynamicFloat` values
4095    pub fn checked_compare(
4096        &self,
4097        rhs: &Self,
4098        quiet: bool,
4099    ) -> Result<(Option<Ordering>, FPState), FPStateMergeFailed> {
4100        let mut fp_state = self.fp_state;
4101        fp_state.checked_merge_assign(rhs.fp_state)?;
4102        let result = self.value.compare(&rhs.value, quiet, Some(&mut fp_state));
4103        Ok((result, fp_state))
4104    }
4105    /// compare two `DynamicFloat` values
4106    pub fn compare_quiet(&self, rhs: &Self) -> (Option<Ordering>, FPState) {
4107        let mut fp_state = self.fp_state;
4108        fp_state.merge_assign(rhs.fp_state);
4109        let result = self.value.compare_quiet(&rhs.value, Some(&mut fp_state));
4110        (result, fp_state)
4111    }
4112    /// compare two `DynamicFloat` values
4113    pub fn checked_compare_quiet(
4114        &self,
4115        rhs: &Self,
4116    ) -> Result<(Option<Ordering>, FPState), FPStateMergeFailed> {
4117        let mut fp_state = self.fp_state;
4118        fp_state.checked_merge_assign(rhs.fp_state)?;
4119        let result = self.value.compare_quiet(&rhs.value, Some(&mut fp_state));
4120        Ok((result, fp_state))
4121    }
4122    /// compare two `DynamicFloat` values
4123    pub fn compare_signaling(&self, rhs: &Self) -> (Option<Ordering>, FPState) {
4124        let mut fp_state = self.fp_state;
4125        fp_state.merge_assign(rhs.fp_state);
4126        let result = self
4127            .value
4128            .compare_signaling(&rhs.value, Some(&mut fp_state));
4129        (result, fp_state)
4130    }
4131    /// compare two `DynamicFloat` values
4132    pub fn checked_compare_signaling(
4133        &self,
4134        rhs: &Self,
4135    ) -> Result<(Option<Ordering>, FPState), FPStateMergeFailed> {
4136        let mut fp_state = self.fp_state;
4137        fp_state.checked_merge_assign(rhs.fp_state)?;
4138        let result = self
4139            .value
4140            .compare_signaling(&rhs.value, Some(&mut fp_state));
4141        Ok((result, fp_state))
4142    }
4143}
4144
4145impl_dynamic_float_from_int_type!(from_bigint_with_traits, from_bigint, BigInt);
4146impl_dynamic_float_from_int_type!(from_biguint_with_traits, from_biguint, BigUint);
4147impl_dynamic_float_from_int_type!(from_u8_with_traits, from_u8, u8);
4148impl_dynamic_float_from_int_type!(from_u16_with_traits, from_u16, u16);
4149impl_dynamic_float_from_int_type!(from_u32_with_traits, from_u32, u32);
4150impl_dynamic_float_from_int_type!(from_u64_with_traits, from_u64, u64);
4151impl_dynamic_float_from_int_type!(from_u128_with_traits, from_u128, u128);
4152impl_dynamic_float_from_int_type!(from_usize_with_traits, from_usize, usize);
4153impl_dynamic_float_from_int_type!(from_i8_with_traits, from_i8, i8);
4154impl_dynamic_float_from_int_type!(from_i16_with_traits, from_i16, i16);
4155impl_dynamic_float_from_int_type!(from_i32_with_traits, from_i32, i32);
4156impl_dynamic_float_from_int_type!(from_i64_with_traits, from_i64, i64);
4157impl_dynamic_float_from_int_type!(from_i128_with_traits, from_i128, i128);
4158impl_dynamic_float_from_int_type!(from_isize_with_traits, from_isize, isize);
4159impl_dynamic_float_to_int_type!(to_bigint, BigInt);
4160impl_dynamic_float_to_int_type!(to_biguint, BigUint);
4161impl_dynamic_float_to_int_type!(to_u8, u8);
4162impl_dynamic_float_to_int_type!(to_u16, u16);
4163impl_dynamic_float_to_int_type!(to_u32, u32);
4164impl_dynamic_float_to_int_type!(to_u64, u64);
4165impl_dynamic_float_to_int_type!(to_u128, u128);
4166impl_dynamic_float_to_int_type!(to_usize, usize);
4167impl_dynamic_float_to_int_type!(to_i8, i8);
4168impl_dynamic_float_to_int_type!(to_i16, i16);
4169impl_dynamic_float_to_int_type!(to_i32, i32);
4170impl_dynamic_float_to_int_type!(to_i64, i64);
4171impl_dynamic_float_to_int_type!(to_i128, i128);
4172impl_dynamic_float_to_int_type!(to_isize, isize);
4173impl_dynamic_float_fn!(
4174    /// compute reciprocal square-root (`1.0 / sqrt(self)`)
4175    rsqrt,
4176    rsqrt,
4177    (&self, rounding_mode: Option<RoundingMode>)
4178);
4179
4180macro_rules! impl_dynamic_float_binary_op_trait {
4181    ($op_trait:ident, $op:ident, $op_assign_trait:ident, $op_assign:ident, $called_fn_name:ident) => {
4182        impl $op_trait for DynamicFloat {
4183            type Output = DynamicFloat;
4184            fn $op(self, rhs: DynamicFloat) -> DynamicFloat {
4185                self.$called_fn_name(&rhs, None)
4186            }
4187        }
4188
4189        impl $op_trait<&'_ DynamicFloat> for DynamicFloat {
4190            type Output = DynamicFloat;
4191            fn $op(self, rhs: &DynamicFloat) -> DynamicFloat {
4192                self.$called_fn_name(rhs, None)
4193            }
4194        }
4195        impl $op_trait<DynamicFloat> for &'_ DynamicFloat {
4196            type Output = DynamicFloat;
4197            fn $op(self, rhs: DynamicFloat) -> DynamicFloat {
4198                self.$called_fn_name(&rhs, None)
4199            }
4200        }
4201
4202        impl<'a, 'b> $op_trait<&'a DynamicFloat> for &'b DynamicFloat {
4203            type Output = DynamicFloat;
4204            fn $op(self, rhs: &DynamicFloat) -> DynamicFloat {
4205                self.$called_fn_name(rhs, None)
4206            }
4207        }
4208
4209        impl $op_assign_trait for DynamicFloat {
4210            fn $op_assign(&mut self, rhs: DynamicFloat) {
4211                *self = self.$called_fn_name(&rhs, None);
4212            }
4213        }
4214
4215        impl $op_assign_trait<&'_ DynamicFloat> for DynamicFloat {
4216            fn $op_assign(&mut self, rhs: &DynamicFloat) {
4217                *self = self.$called_fn_name(rhs, None);
4218            }
4219        }
4220    };
4221}
4222
4223impl_dynamic_float_binary_op_trait!(Add, add, AddAssign, add_assign, add_with_rounding_mode);
4224impl_dynamic_float_binary_op_trait!(Sub, sub, SubAssign, sub_assign, sub_with_rounding_mode);
4225impl_dynamic_float_binary_op_trait!(Mul, mul, MulAssign, mul_assign, mul_with_rounding_mode);
4226impl_dynamic_float_binary_op_trait!(Div, div, DivAssign, div_assign, div_with_rounding_mode);
4227
4228impl Neg for &'_ DynamicFloat {
4229    type Output = DynamicFloat;
4230    fn neg(self) -> DynamicFloat {
4231        let mut retval = self.clone();
4232        retval.neg_assign();
4233        retval
4234    }
4235}
4236
4237impl Neg for DynamicFloat {
4238    type Output = DynamicFloat;
4239    fn neg(mut self) -> DynamicFloat {
4240        self.neg_assign();
4241        self
4242    }
4243}
4244
4245#[cfg(test)]
4246mod tests {
4247    #![allow(clippy::cognitive_complexity)]
4248    use super::*;
4249
4250    #[test]
4251    fn test_debug() {
4252        assert_eq!(
4253            &format!("{:?}", F16::from_bits(0x0000)),
4254            "Float { traits: F16Traits, bits: 0x0000, sign: Positive, \
4255             exponent_field: 0x00, mantissa_field: 0x000, class: PositiveZero }",
4256        );
4257        assert_eq!(
4258            &format!("{:?}", F16::from_bits(0x8000)),
4259            "Float { traits: F16Traits, bits: 0x8000, sign: Negative, \
4260             exponent_field: 0x00, mantissa_field: 0x000, class: NegativeZero }",
4261        );
4262        assert_eq!(
4263            &format!("{:?}", F16::from_bits(0xFC00)),
4264            "Float { traits: F16Traits, bits: 0xFC00, sign: Negative, \
4265             exponent_field: 0x1F, mantissa_field: 0x000, class: NegativeInfinity }",
4266        );
4267        assert_eq!(
4268            &format!("{:?}", F16::from_bits(0xFE00)),
4269            "Float { traits: F16Traits, bits: 0xFE00, sign: Negative, \
4270             exponent_field: 0x1F, mantissa_field: 0x200, class: QuietNaN }",
4271        );
4272        assert_eq!(
4273            &format!("{:?}", F16::from_bits(0x0001)),
4274            "Float { traits: F16Traits, bits: 0x0001, sign: Positive, \
4275             exponent_field: 0x00, mantissa_field: 0x001, class: PositiveSubnormal }",
4276        );
4277        assert_eq!(
4278            &format!("{:?}", F16::from_bits(0x3C00)),
4279            "Float { traits: F16Traits, bits: 0x3C00, sign: Positive, \
4280             exponent_field: 0x0F, mantissa_field: 0x000, class: PositiveNormal }",
4281        );
4282        assert_eq!(
4283            &format!(
4284                "{:?}",
4285                F16WithPlatformProperties::from_bits_and_traits(
4286                    0x1234,
4287                    F16WithPlatformPropertiesTraits(PlatformProperties::RISC_V)
4288                )
4289            ),
4290            "Float { traits: F16WithPlatformPropertiesTraits(PlatformProperties::RISC_V), \
4291             bits: 0x1234, sign: Positive, exponent_field: 0x04, \
4292             mantissa_field: 0x234, class: PositiveNormal }",
4293        );
4294        assert_eq!(
4295            &format!(
4296                "{:?}",
4297                F16WithPlatformProperties::from_bits_and_traits(
4298                    0x1234,
4299                    F16WithPlatformPropertiesTraits(PlatformProperties::SPARC)
4300                )
4301            ),
4302            "Float { traits: F16WithPlatformPropertiesTraits(PlatformProperties::SPARC), \
4303             bits: 0x1234, sign: Positive, exponent_field: 0x04, \
4304             mantissa_field: 0x234, class: PositiveNormal }",
4305        );
4306        assert_eq!(
4307            &format!(
4308                "{:?}",
4309                F16WithPlatformProperties::from_bits_and_traits(
4310                    0x1234,
4311                    F16WithPlatformPropertiesTraits(PlatformProperties::X86_SSE)
4312                )
4313            ),
4314            "Float { traits: F16WithPlatformPropertiesTraits(PlatformProperties::X86_SSE), \
4315             bits: 0x1234, sign: Positive, exponent_field: 0x04, \
4316             mantissa_field: 0x234, class: PositiveNormal }",
4317        );
4318        assert_eq!(
4319            &format!(
4320                "{:?}",
4321                F16WithPlatformProperties::from_bits_and_traits(
4322                    0x1234,
4323                    F16WithPlatformPropertiesTraits(PlatformProperties::HPPA)
4324                )
4325            ),
4326            "Float { traits: F16WithPlatformPropertiesTraits(PlatformProperties::HPPA), \
4327             bits: 0x1234, sign: Positive, exponent_field: 0x04, \
4328             mantissa_field: 0x234, class: PositiveNormal }",
4329        );
4330        assert_eq!(
4331            &format!(
4332                "{:?}",
4333                F16WithPlatformProperties::from_bits_and_traits(
4334                    0x1234,
4335                    F16WithPlatformPropertiesTraits(PlatformProperties::MIPS_LEGACY)
4336                )
4337            ),
4338            "Float { traits: F16WithPlatformPropertiesTraits(PlatformProperties::MIPS_LEGACY), \
4339             bits: 0x1234, sign: Positive, exponent_field: 0x04, \
4340             mantissa_field: 0x234, class: PositiveNormal }",
4341        );
4342        assert_eq!(
4343            &format!(
4344                "{:?}",
4345                F16WithPlatformProperties::from_bits_and_traits(
4346                    0x1234,
4347                    F16WithPlatformPropertiesTraits(PlatformProperties {
4348                        canonical_nan_sign: Sign::Negative,
4349                        ..PlatformProperties::MIPS_LEGACY
4350                    })
4351                )
4352            ),
4353            "Float { traits: F16WithPlatformPropertiesTraits(PlatformProperties { \
4354             canonical_nan_sign: Negative, canonical_nan_mantissa_msb: false, \
4355             canonical_nan_mantissa_second_to_msb: true, \
4356             canonical_nan_mantissa_rest: true, \
4357             std_bin_ops_nan_propagation_mode: FirstSecondPreferringSNaN, \
4358             fma_nan_propagation_mode: FirstSecondThirdPreferringSNaN, \
4359             fma_inf_zero_qnan_result: CanonicalAndGenerateInvalid, \
4360             round_to_integral_nan_propagation_mode: First, \
4361             next_up_or_down_nan_propagation_mode: First, \
4362             scale_b_nan_propagation_mode: First, \
4363             sqrt_nan_propagation_mode: First, \
4364             float_to_float_conversion_nan_propagation_mode: RetainMostSignificantBits, \
4365             rsqrt_nan_propagation_mode: First, \
4366             quiet_nan_format: MIPSLegacy }), \
4367             bits: 0x1234, sign: Positive, exponent_field: 0x04, \
4368             mantissa_field: 0x234, class: PositiveNormal }",
4369        );
4370    }
4371
4372    #[test]
4373    fn test_class() {
4374        use FloatClass::*;
4375        assert_eq!(F16::from_bits(0x0000).class(), PositiveZero);
4376        assert_eq!(F16::from_bits(0x0001).class(), PositiveSubnormal);
4377        assert_eq!(F16::from_bits(0x03FF).class(), PositiveSubnormal);
4378        assert_eq!(F16::from_bits(0x0400).class(), PositiveNormal);
4379        assert_eq!(F16::from_bits(0x3C00).class(), PositiveNormal);
4380        assert_eq!(F16::from_bits(0x7BFF).class(), PositiveNormal);
4381        assert_eq!(F16::from_bits(0x7C00).class(), PositiveInfinity);
4382        assert_eq!(F16::from_bits(0x7C01).class(), SignalingNaN);
4383        assert_eq!(F16::from_bits(0x7DFF).class(), SignalingNaN);
4384        assert_eq!(F16::from_bits(0x7E00).class(), QuietNaN);
4385        assert_eq!(F16::from_bits(0x7FFF).class(), QuietNaN);
4386        assert_eq!(F16::from_bits(0x8000).class(), NegativeZero);
4387        assert_eq!(F16::from_bits(0x8001).class(), NegativeSubnormal);
4388        assert_eq!(F16::from_bits(0x83FF).class(), NegativeSubnormal);
4389        assert_eq!(F16::from_bits(0x8400).class(), NegativeNormal);
4390        assert_eq!(F16::from_bits(0xBC00).class(), NegativeNormal);
4391        assert_eq!(F16::from_bits(0xFBFF).class(), NegativeNormal);
4392        assert_eq!(F16::from_bits(0xFC00).class(), NegativeInfinity);
4393        assert_eq!(F16::from_bits(0xFC01).class(), SignalingNaN);
4394        assert_eq!(F16::from_bits(0xFDFF).class(), SignalingNaN);
4395        assert_eq!(F16::from_bits(0xFE00).class(), QuietNaN);
4396        assert_eq!(F16::from_bits(0xFFFF).class(), QuietNaN);
4397        assert_eq!(
4398            Float::from_bits_and_traits(
4399                0x7C01,
4400                F16WithPlatformPropertiesTraits(PlatformProperties::MIPS_LEGACY)
4401            )
4402            .class(),
4403            QuietNaN
4404        );
4405        assert_eq!(
4406            Float::from_bits_and_traits(
4407                0x7DFF,
4408                F16WithPlatformPropertiesTraits(PlatformProperties::MIPS_LEGACY)
4409            )
4410            .class(),
4411            QuietNaN
4412        );
4413        assert_eq!(
4414            Float::from_bits_and_traits(
4415                0x7E00,
4416                F16WithPlatformPropertiesTraits(PlatformProperties::MIPS_LEGACY)
4417            )
4418            .class(),
4419            SignalingNaN
4420        );
4421        assert_eq!(
4422            Float::from_bits_and_traits(
4423                0x7FFF,
4424                F16WithPlatformPropertiesTraits(PlatformProperties::MIPS_LEGACY)
4425            )
4426            .class(),
4427            SignalingNaN
4428        );
4429        assert_eq!(
4430            Float::from_bits_and_traits(
4431                0xFC01,
4432                F16WithPlatformPropertiesTraits(PlatformProperties::MIPS_LEGACY)
4433            )
4434            .class(),
4435            QuietNaN
4436        );
4437        assert_eq!(
4438            Float::from_bits_and_traits(
4439                0xFDFF,
4440                F16WithPlatformPropertiesTraits(PlatformProperties::MIPS_LEGACY)
4441            )
4442            .class(),
4443            QuietNaN
4444        );
4445        assert_eq!(
4446            Float::from_bits_and_traits(
4447                0xFE00,
4448                F16WithPlatformPropertiesTraits(PlatformProperties::MIPS_LEGACY)
4449            )
4450            .class(),
4451            SignalingNaN
4452        );
4453        assert_eq!(
4454            Float::from_bits_and_traits(
4455                0xFFFF,
4456                F16WithPlatformPropertiesTraits(PlatformProperties::MIPS_LEGACY)
4457            )
4458            .class(),
4459            SignalingNaN
4460        );
4461    }
4462
4463    #[test]
4464    fn test_to_ratio() {
4465        macro_rules! test_case {
4466            ($value:expr, $expected_ratio:expr) => {
4467                let value: F16 = $value;
4468                let expected_ratio: Option<Ratio<i128>> = $expected_ratio;
4469                println!("value: {:?}", value);
4470                println!("expected_ratio: {:?}", expected_ratio);
4471                let ratio = value.to_ratio();
4472                println!("ratio: {:?}", ratio.as_ref().map(ToString::to_string));
4473                let expected_ratio = expected_ratio.map(|v| {
4474                    let (n, d) = v.into();
4475                    Ratio::new(n.into(), d.into())
4476                });
4477                assert!(ratio == expected_ratio);
4478            };
4479        }
4480
4481        let r = |n, d| Some(Ratio::new(n, d));
4482
4483        test_case!(F16::from_bits(0x0000), r(0, 1));
4484        test_case!(F16::from_bits(0x0001), r(1, 1 << 24));
4485        test_case!(F16::from_bits(0x03FF), r(1023, 1 << 24));
4486        test_case!(F16::from_bits(0x0400), r(1, 1 << 14));
4487        test_case!(F16::from_bits(0x3C00), r(1, 1));
4488        test_case!(F16::from_bits(0x7BFF), r(65504, 1));
4489        test_case!(F16::from_bits(0x7C00), None);
4490        test_case!(F16::from_bits(0x7C01), None);
4491        test_case!(F16::from_bits(0x7DFF), None);
4492        test_case!(F16::from_bits(0x7E00), None);
4493        test_case!(F16::from_bits(0x7FFF), None);
4494        test_case!(F16::from_bits(0x8000), r(0, 1));
4495        test_case!(F16::from_bits(0x8001), r(-1, 1 << 24));
4496        test_case!(F16::from_bits(0x83FF), r(-1023, 1 << 24));
4497        test_case!(F16::from_bits(0x8400), r(-1, 1 << 14));
4498        test_case!(F16::from_bits(0xBC00), r(-1, 1));
4499        test_case!(F16::from_bits(0xFBFF), r(-65504, 1));
4500        test_case!(F16::from_bits(0xFC00), None);
4501        test_case!(F16::from_bits(0xFC01), None);
4502        test_case!(F16::from_bits(0xFDFF), None);
4503        test_case!(F16::from_bits(0xFE00), None);
4504        test_case!(F16::from_bits(0xFFFF), None);
4505    }
4506
4507    #[test]
4508    fn test_log_b() {
4509        macro_rules! test_case {
4510            ($value:expr, $expected_result:expr) => {
4511                let value: F16 = $value;
4512                let expected_result: Option<i32> = $expected_result;
4513                let expected_status_flags: StatusFlags = if expected_result.is_some() {
4514                    StatusFlags::empty()
4515                } else {
4516                    StatusFlags::INVALID_OPERATION
4517                };
4518                println!("value: {:?}", value);
4519                println!("expected_result: {:?}", expected_result);
4520                println!("expected_status_flags: {:?}", expected_status_flags);
4521                let mut fp_state = FPState::default();
4522                let result = value.log_b(Some(&mut fp_state));
4523                println!("result: {:?}", result.as_ref().map(ToString::to_string));
4524                let expected_result: Option<BigInt> = expected_result.map(Into::into);
4525                println!("status_flags: {:?}", fp_state.status_flags);
4526                assert!(result == expected_result);
4527                assert!(fp_state.status_flags == expected_status_flags);
4528            };
4529        }
4530
4531        test_case!(F16::from_bits(0x0000), None);
4532        test_case!(F16::from_bits(0x0001), Some(-24));
4533        test_case!(F16::from_bits(0x0002), Some(-23));
4534        test_case!(F16::from_bits(0x03FF), Some(-15));
4535        test_case!(F16::from_bits(0x0400), Some(-14));
4536        test_case!(F16::from_bits(0x3C00), Some(0));
4537        test_case!(F16::from_bits(0x7BFF), Some(15));
4538        test_case!(F16::from_bits(0x7C00), None);
4539        test_case!(F16::from_bits(0x7C01), None);
4540        test_case!(F16::from_bits(0x7DFF), None);
4541        test_case!(F16::from_bits(0x7E00), None);
4542        test_case!(F16::from_bits(0x7FFF), None);
4543        test_case!(F16::from_bits(0x8000), None);
4544        test_case!(F16::from_bits(0x8001), Some(-24));
4545        test_case!(F16::from_bits(0x8002), Some(-23));
4546        test_case!(F16::from_bits(0x83FF), Some(-15));
4547        test_case!(F16::from_bits(0x8400), Some(-14));
4548        test_case!(F16::from_bits(0xBC00), Some(0));
4549        test_case!(F16::from_bits(0xFBFF), Some(15));
4550        test_case!(F16::from_bits(0xFC00), None);
4551        test_case!(F16::from_bits(0xFC01), None);
4552        test_case!(F16::from_bits(0xFDFF), None);
4553        test_case!(F16::from_bits(0xFE00), None);
4554        test_case!(F16::from_bits(0xFFFF), None);
4555    }
4556
4557    // FIXME: add more tests
4558}
4559
4560macro_rules! doctest {
4561    ($x:expr) => {
4562        #[doc = $x]
4563        extern {}
4564    };
4565}
4566
4567doctest!(include_str!("../README.md"));