fixed/
convert.rs

1// Copyright © 2018–2025 Trevor Spiteri
2
3// This library is free software: you can redistribute it and/or
4// modify it under the terms of either
5//
6//   * the Apache License, Version 2.0 or
7//   * the MIT License
8//
9// at your option.
10//
11// You should have recieved copies of the Apache License and the MIT
12// License along with the library. If not, see
13// <https://www.apache.org/licenses/LICENSE-2.0> and
14// <https://opensource.org/licenses/MIT>.
15
16#![allow(deprecated)]
17
18use crate::int_helper::IntFixed;
19use crate::traits::{FromFixed, LosslessTryFrom, LossyFrom, ToFixed};
20use crate::types::extra::{
21    Diff, IsLessOrEqual, LeEqU8, LeEqU16, LeEqU32, LeEqU64, LeEqU128, True, U0, U1, U7, U8, U15,
22    U16, U24, U31, U32, U63, U64, U127, U128,
23};
24use crate::{
25    F128, F128Bits, FixedI8, FixedI16, FixedI32, FixedI64, FixedI128, FixedU8, FixedU16, FixedU32,
26    FixedU64, FixedU128,
27};
28use core::ops::Sub;
29use half::{bf16 as half_bf16, f16 as half_f16};
30
31macro_rules! convert {
32    (
33        ($SrcU:ident, $SrcI:ident, $SrcBits:ident, $SrcLeEqU:ident) ->
34            ($DstU:ident, $DstI:ident, $DstBits:ident, $DstBitsM1:ident, $DstLeEqU:ident)
35    ) => {
36        impl<FracSrc: $SrcLeEqU, FracDst: $DstLeEqU> From<$SrcU<FracSrc>> for $DstU<FracDst>
37        where
38            FracSrc: IsLessOrEqual<FracDst, Output = True>,
39            $SrcBits: Sub<FracSrc>,
40            $DstBits: Sub<FracDst>,
41            Diff<$SrcBits, FracSrc>: IsLessOrEqual<Diff<$DstBits, FracDst>, Output = True>,
42        {
43            /// Converts a fixed-pint number.
44            ///
45            /// This conversion never fails (infallible) and does not
46            /// lose any precision (lossless).
47            #[inline]
48            fn from(src: $SrcU<FracSrc>) -> Self {
49                let unshifted = Self::from_bits(src.to_bits().into()).to_bits();
50                let shift = FracDst::U32 - FracSrc::U32;
51                Self::from_bits(unshifted << shift)
52            }
53        }
54
55        impl<FracSrc: $SrcLeEqU, FracDst: $DstLeEqU> From<$SrcI<FracSrc>> for $DstI<FracDst>
56        where
57            FracSrc: IsLessOrEqual<FracDst, Output = True>,
58            $SrcBits: Sub<FracSrc>,
59            $DstBits: Sub<FracDst>,
60            Diff<$SrcBits, FracSrc>: IsLessOrEqual<Diff<$DstBits, FracDst>, Output = True>,
61        {
62            /// Converts a fixed-pint number.
63            ///
64            /// This conversion never fails (infallible) and does not
65            /// lose any precision (lossless).
66            #[inline]
67            fn from(src: $SrcI<FracSrc>) -> Self {
68                let unshifted = Self::from_bits(src.to_bits().into()).to_bits();
69                let shift = FracDst::U32 - FracSrc::U32;
70                Self::from_bits(unshifted << shift)
71            }
72        }
73
74        impl<FracSrc: $SrcLeEqU, FracDst: $DstLeEqU> From<$SrcU<FracSrc>> for $DstI<FracDst>
75        where
76            FracSrc: IsLessOrEqual<FracDst, Output = True>,
77            $SrcBits: Sub<FracSrc>,
78            $DstBitsM1: Sub<FracDst>,
79            Diff<$SrcBits, FracSrc>: IsLessOrEqual<Diff<$DstBitsM1, FracDst>, Output = True>,
80        {
81            /// Converts a fixed-pint number.
82            ///
83            /// This conversion never fails (infallible) and does not
84            /// lose any precision (lossless).
85            #[inline]
86            fn from(src: $SrcU<FracSrc>) -> Self {
87                let unshifted = Self::from_bits(src.to_bits().into()).to_bits();
88                let shift = FracDst::U32 - FracSrc::U32;
89                Self::from_bits(unshifted << shift)
90            }
91        }
92    };
93}
94
95macro_rules! convert_lossless {
96    (
97        ($Src:ident, $SrcBits:ident, $SrcLeEqU:ident) ->
98            ($Dst:ident, $DstBits:ident, $DstLeEqU:ident)
99    ) => {
100        // lossless because Src::FRAC_NBITS <= Dst::FRAC_NBITS
101        impl<FracSrc: $SrcLeEqU, FracDst: $DstLeEqU> LosslessTryFrom<$Src<FracSrc>>
102            for $Dst<FracDst>
103        where
104            FracSrc: IsLessOrEqual<FracDst, Output = True>,
105        {
106            /// Converts a fixed-pint number.
107            ///
108            /// This conversion may fail (fallible) but does not lose
109            /// precision (lossless).
110            #[inline]
111            fn lossless_try_from(src: $Src<FracSrc>) -> Option<Self> {
112                Self::checked_from_fixed(src)
113            }
114        }
115    };
116    ($Src:ident, $SrcBits:ident, $SrcLeEqU:ident) => {
117        convert_lossless! { ($Src, $SrcBits, $SrcLeEqU) -> (FixedI8, U8, LeEqU8) }
118        convert_lossless! { ($Src, $SrcBits, $SrcLeEqU) -> (FixedI16, U16, LeEqU16) }
119        convert_lossless! { ($Src, $SrcBits, $SrcLeEqU) -> (FixedI32, U32, LeEqU32) }
120        convert_lossless! { ($Src, $SrcBits, $SrcLeEqU) -> (FixedI64, U64, LeEqU64) }
121        convert_lossless! { ($Src, $SrcBits, $SrcLeEqU) -> (FixedI128, U128, LeEqU128) }
122        convert_lossless! { ($Src, $SrcBits, $SrcLeEqU) -> (FixedU8, U8, LeEqU8) }
123        convert_lossless! { ($Src, $SrcBits, $SrcLeEqU) -> (FixedU16, U16, LeEqU16) }
124        convert_lossless! { ($Src, $SrcBits, $SrcLeEqU) -> (FixedU32, U32, LeEqU32) }
125        convert_lossless! { ($Src, $SrcBits, $SrcLeEqU) -> (FixedU64, U64, LeEqU64) }
126        convert_lossless! { ($Src, $SrcBits, $SrcLeEqU) -> (FixedU128, U128, LeEqU128) }
127    };
128}
129
130macro_rules! convert_lossy {
131    (
132        ($SrcU:ident, $SrcI:ident, $SrcBits:ident, $SrcLeEqU:ident) ->
133            ($DstU:ident, $DstI:ident, $DstBits:ident, $DstBitsM1:ident, $DstLeEqU:ident)
134    ) => {
135        // unsigned -> unsigned, infallible because Src::INT_NBITS <= Dst::INT_NBITS
136        impl<FracSrc: $SrcLeEqU, FracDst: $DstLeEqU> LossyFrom<$SrcU<FracSrc>> for $DstU<FracDst>
137        where
138            $SrcBits: Sub<FracSrc>,
139            $DstBits: Sub<FracDst>,
140            Diff<$SrcBits, FracSrc>: IsLessOrEqual<Diff<$DstBits, FracDst>, Output = True>,
141        {
142            /// Converts a fixed-pint number.
143            ///
144            /// This conversion never fails (infallible) but may lose
145            /// precision (lossy). Any fractional bits in the source
146            /// that cannot be represented in the destination are
147            /// discarded, which rounds towards &minus;∞.
148            #[inline]
149            fn lossy_from(src: $SrcU<FracSrc>) -> Self {
150                src.to_num()
151            }
152        }
153
154        // signed -> signed, infallible because Src::INT_NBITS <= Dst::INT_NBITS
155        impl<FracSrc: $SrcLeEqU, FracDst: $DstLeEqU> LossyFrom<$SrcI<FracSrc>> for $DstI<FracDst>
156        where
157            $SrcBits: Sub<FracSrc>,
158            $DstBits: Sub<FracDst>,
159            Diff<$SrcBits, FracSrc>: IsLessOrEqual<Diff<$DstBits, FracDst>, Output = True>,
160        {
161            /// Converts a fixed-pint number.
162            ///
163            /// This conversion never fails (infallible) but may lose
164            /// precision (lossy). Any fractional bits in the source
165            /// that cannot be represented in the destination are
166            /// discarded, which rounds towards &minus;∞.
167            #[inline]
168            fn lossy_from(src: $SrcI<FracSrc>) -> Self {
169                src.to_num()
170            }
171        }
172
173        // signed -> signed, infallible because Src::INT_NBITS <= Dst::INT_NBITS - 1
174        impl<FracSrc: $SrcLeEqU, FracDst: $DstLeEqU> LossyFrom<$SrcU<FracSrc>> for $DstI<FracDst>
175        where
176            $SrcBits: Sub<FracSrc>,
177            $DstBitsM1: Sub<FracDst>,
178            Diff<$SrcBits, FracSrc>: IsLessOrEqual<Diff<$DstBitsM1, FracDst>, Output = True>,
179        {
180            /// Converts a fixed-pint number.
181            ///
182            /// This conversion never fails (infallible) but may lose
183            /// precision (lossy). Any fractional bits in the source
184            /// that cannot be represented in the destination are
185            /// discarded, which rounds towards &minus;∞.
186            #[inline]
187            fn lossy_from(src: $SrcU<FracSrc>) -> Self {
188                src.to_num()
189            }
190        }
191    };
192    ($SrcU:ident, $SrcI:ident, $SrcBits:ident, $SrcLeEqU:ident) => {
193        convert_lossy! {
194            ($SrcU, $SrcI, $SrcBits, $SrcLeEqU) -> (FixedU8, FixedI8, U8, U7, LeEqU8)
195        }
196        convert_lossy! {
197            ($SrcU, $SrcI, $SrcBits, $SrcLeEqU) -> (FixedU16, FixedI16, U16, U15, LeEqU16)
198        }
199        convert_lossy! {
200            ($SrcU, $SrcI, $SrcBits, $SrcLeEqU) -> (FixedU32, FixedI32, U32, U31, LeEqU32)
201        }
202        convert_lossy! {
203            ($SrcU, $SrcI, $SrcBits, $SrcLeEqU) -> (FixedU64, FixedI64, U64, U63, LeEqU64)
204        }
205        convert_lossy! {
206            ($SrcU, $SrcI, $SrcBits, $SrcLeEqU) -> (FixedU128, FixedI128, U128, U127, LeEqU128)
207        }
208    };
209}
210
211convert! { (FixedU8, FixedI8, U8, LeEqU8) -> (FixedU16, FixedI16, U16, U15, LeEqU16) }
212convert! { (FixedU8, FixedI8, U8, LeEqU8) -> (FixedU32, FixedI32, U32, U31, LeEqU32) }
213convert! { (FixedU8, FixedI8, U8, LeEqU8) -> (FixedU64, FixedI64, U64, U63, LeEqU64) }
214convert! { (FixedU8, FixedI8, U8, LeEqU8) -> (FixedU128, FixedI128, U128, U127, LeEqU128) }
215
216convert! { (FixedU16, FixedI16, U16, LeEqU16) -> (FixedU32, FixedI32, U32, U31, LeEqU32) }
217convert! { (FixedU16, FixedI16, U16, LeEqU16) -> (FixedU64, FixedI64, U64, U63, LeEqU64) }
218convert! { (FixedU16, FixedI16, U16, LeEqU16) -> (FixedU128, FixedI128, U128, U127, LeEqU128) }
219
220convert! { (FixedU32, FixedI32, U32, LeEqU32) -> (FixedU64, FixedI64, U64, U63, LeEqU64) }
221convert! { (FixedU32, FixedI32, U32, LeEqU32) -> (FixedU128, FixedI128, U128, U127, LeEqU128) }
222
223convert! { (FixedU64, FixedI64, U64, LeEqU64) -> (FixedU128, FixedI128, U128, U127, LeEqU128) }
224
225convert_lossless! { FixedI8, U8, LeEqU8 }
226convert_lossless! { FixedI16, U16, LeEqU16 }
227convert_lossless! { FixedI32, U32, LeEqU32 }
228convert_lossless! { FixedI64, U64, LeEqU64 }
229convert_lossless! { FixedI128, U128, LeEqU128 }
230convert_lossless! { FixedU8, U8, LeEqU8 }
231convert_lossless! { FixedU16, U16, LeEqU16 }
232convert_lossless! { FixedU32, U32, LeEqU32 }
233convert_lossless! { FixedU64, U64, LeEqU64 }
234convert_lossless! { FixedU128, U128, LeEqU128 }
235
236convert_lossy! { FixedU8, FixedI8, U8, LeEqU8 }
237convert_lossy! { FixedU16, FixedI16, U16, LeEqU16 }
238convert_lossy! { FixedU32, FixedI32, U32, LeEqU32 }
239convert_lossy! { FixedU64, FixedI64, U64, LeEqU64 }
240convert_lossy! { FixedU128, FixedI128, U128, LeEqU128 }
241
242macro_rules! int_to_fixed {
243    ($Src:ident, $Dst:ident, $LeEqU:ident) => {
244        impl<Frac: $LeEqU> LosslessTryFrom<$Src> for $Dst<Frac> {
245            /// Converts an integer to a fixed-point number.
246            ///
247            /// This conversion may fail (fallible) but cannot lose
248            /// any fractional bits (lossless).
249            #[inline]
250            fn lossless_try_from(src: $Src) -> Option<Self> {
251                src.checked_to_fixed()
252            }
253        }
254    };
255
256    ($Src:ident $(, $Dst:ty)?) => {
257        $(impl From<$Src> for $Dst {
258            /// Converts an integer to a fixed-point number.
259            ///
260            /// This conversion never fails (infallible) and cannot
261            /// lose any fractional bits (lossless).
262            #[inline]
263            fn from(src: $Src) -> Self {
264                Self::from_bits(src)
265            }
266        })?
267
268        int_to_fixed! { $Src, FixedI8, LeEqU8 }
269        int_to_fixed! { $Src, FixedI16, LeEqU16 }
270        int_to_fixed! { $Src, FixedI32, LeEqU32 }
271        int_to_fixed! { $Src, FixedI64, LeEqU64 }
272        int_to_fixed! { $Src, FixedI128, LeEqU128 }
273        int_to_fixed! { $Src, FixedU8, LeEqU8 }
274        int_to_fixed! { $Src, FixedU16, LeEqU16 }
275        int_to_fixed! { $Src, FixedU32, LeEqU32 }
276        int_to_fixed! { $Src, FixedU64, LeEqU64 }
277        int_to_fixed! { $Src, FixedU128, LeEqU128 }
278
279        $(impl LossyFrom<$Src> for $Dst {
280            /// Converts an integer to a fixed-point number.
281            ///
282            /// This conversion never fails (infallible) and actually
283            /// does not lose any precision (lossless).
284            #[inline]
285            fn lossy_from(src: $Src) -> Self {
286                Self::from_bits(src)
287            }
288        })?
289    };
290}
291
292int_to_fixed! { bool }
293int_to_fixed! { i8, FixedI8<U0> }
294int_to_fixed! { i16, FixedI16<U0> }
295int_to_fixed! { i32, FixedI32<U0> }
296int_to_fixed! { i64, FixedI64<U0> }
297int_to_fixed! { i128, FixedI128<U0> }
298int_to_fixed! { isize }
299int_to_fixed! { u8, FixedU8<U0> }
300int_to_fixed! { u16, FixedU16<U0> }
301int_to_fixed! { u32, FixedU32<U0> }
302int_to_fixed! { u64, FixedU64<U0> }
303int_to_fixed! { u128, FixedU128<U0> }
304int_to_fixed! { usize }
305
306macro_rules! int_to_wider_fixed {
307    (
308        ($SrcU:ident, $SrcI:ident, $SrcBits:ident, $SrcLeEqU:ident) ->
309            ($DstU:ident, $DstI:ident, $DstBits:ident, $DstBitsM1:ident, $DstLeEqU:ident)
310    ) => {
311        impl<FracDst: $DstLeEqU> From<$SrcU> for $DstU<FracDst>
312        where
313            $DstBits: Sub<FracDst>,
314            $SrcBits: IsLessOrEqual<Diff<$DstBits, FracDst>, Output = True>,
315        {
316            /// Converts an integer to a fixed-point number.
317            ///
318            /// This conversion never fails (infallible) and cannot
319            /// lose any fractional bits, so it is actually lossless.
320            #[inline]
321            fn from(src: $SrcU) -> Self {
322                let unshifted = Self::from_bits(src.into()).to_bits();
323                let shift = FracDst::U32;
324                Self::from_bits(unshifted << shift)
325            }
326        }
327
328        impl<FracDst: $DstLeEqU> From<$SrcI> for $DstI<FracDst>
329        where
330            $DstBits: Sub<FracDst>,
331            $SrcBits: IsLessOrEqual<Diff<$DstBits, FracDst>, Output = True>,
332        {
333            /// Converts an integer to a fixed-point number.
334            ///
335            /// This conversion never fails (infallible) and cannot
336            /// lose any fractional bits, so it is actually lossless.
337            #[inline]
338            fn from(src: $SrcI) -> Self {
339                let unshifted = Self::from_bits(src.into()).to_bits();
340                let shift = FracDst::U32;
341                Self::from_bits(unshifted << shift)
342            }
343        }
344
345        impl<FracDst: $DstLeEqU> From<$SrcU> for $DstI<FracDst>
346        where
347            $DstBitsM1: Sub<FracDst>,
348            $SrcBits: IsLessOrEqual<Diff<$DstBitsM1, FracDst>, Output = True>,
349        {
350            /// Converts an integer to a fixed-point number.
351            ///
352            /// This conversion never fails (infallible) and cannot
353            /// lose any fractional bits, so it is actually lossless.
354            #[inline]
355            fn from(src: $SrcU) -> Self {
356                let unshifted = Self::from_bits(src.into()).to_bits();
357                let shift = FracDst::U32;
358                Self::from_bits(unshifted << shift)
359            }
360        }
361
362        impl<FracDst: $DstLeEqU> LossyFrom<$SrcU> for $DstU<FracDst>
363        where
364            $DstBits: Sub<FracDst>,
365            $SrcBits: IsLessOrEqual<Diff<$DstBits, FracDst>, Output = True>,
366        {
367            /// Converts an integer to a fixed-point number.
368            ///
369            /// This conversion never fails (infallible) and cannot
370            /// lose any fractional bits, so it is actually lossless.
371            #[inline]
372            fn lossy_from(src: $SrcU) -> Self {
373                src.into()
374            }
375        }
376
377        impl<FracDst: $DstLeEqU> LossyFrom<$SrcI> for $DstI<FracDst>
378        where
379            $DstBits: Sub<FracDst>,
380            $SrcBits: IsLessOrEqual<Diff<$DstBits, FracDst>, Output = True>,
381        {
382            /// Converts an integer to a fixed-point number.
383            ///
384            /// This conversion never fails (infallible) and cannot
385            /// lose any fractional bits, so it is actually lossless.
386            #[inline]
387            fn lossy_from(src: $SrcI) -> Self {
388                src.into()
389            }
390        }
391
392        impl<FracDst: $DstLeEqU> LossyFrom<$SrcU> for $DstI<FracDst>
393        where
394            $DstBitsM1: Sub<FracDst>,
395            $SrcBits: IsLessOrEqual<Diff<$DstBitsM1, FracDst>, Output = True>,
396        {
397            /// Converts an integer to a fixed-point number.
398            ///
399            /// This conversion never fails (infallible) and cannot
400            /// lose any fractional bits, so it is actually lossless.
401            #[inline]
402            fn lossy_from(src: $SrcU) -> Self {
403                src.into()
404            }
405        }
406    };
407}
408
409int_to_wider_fixed! { (u8, i8, U8, LeEqU8) -> (FixedU16, FixedI16, U16, U15, LeEqU16) }
410int_to_wider_fixed! { (u8, i8, U8, LeEqU8) -> (FixedU32, FixedI32, U32, U31, LeEqU32) }
411int_to_wider_fixed! { (u8, i8, U8, LeEqU8) -> (FixedU64, FixedI64, U64, U63, LeEqU64) }
412int_to_wider_fixed! { (u8, i8, U8, LeEqU8) -> (FixedU128, FixedI128, U128, U127, LeEqU128) }
413int_to_wider_fixed! { (u16, i16, U16, LeEqU16) -> (FixedU32, FixedI32, U32, U31, LeEqU32) }
414int_to_wider_fixed! { (u16, i16, U16, LeEqU16) -> (FixedU64, FixedI64, U64, U63, LeEqU64) }
415int_to_wider_fixed! { (u16, i16, U16, LeEqU16) -> (FixedU128, FixedI128, U128, U127, LeEqU128) }
416int_to_wider_fixed! { (u32, i32, U32, LeEqU32) -> (FixedU64, FixedI64, U64, U63, LeEqU64) }
417int_to_wider_fixed! { (u32, i32, U32, LeEqU32) -> (FixedU128, FixedI128, U128, U127, LeEqU128) }
418int_to_wider_fixed! { (u64, i64, U64, LeEqU64) -> (FixedU128, FixedI128, U128, U127, LeEqU128) }
419
420macro_rules! bool_to_fixed {
421    ($DstU:ident, $DstI:ident, $DstBits:ident, $DstBitsM1:ident, $DstLeEqU:ident) => {
422        impl<FracDst: $DstLeEqU> From<bool> for $DstU<FracDst>
423        where
424            $DstBits: Sub<FracDst>,
425            U1: IsLessOrEqual<Diff<$DstBits, FracDst>, Output = True>,
426        {
427            /// Converts a [`bool`] to a fixed-point number.
428            ///
429            /// This conversion never fails (infallible) and cannot
430            /// lose any fractional bits (lossless).
431            #[inline]
432            fn from(src: bool) -> Self {
433                let unshifted = Self::from_bits(src.into()).to_bits();
434                let shift = FracDst::U32;
435                Self::from_bits(unshifted << shift)
436            }
437        }
438
439        impl<FracDst: $DstLeEqU> From<bool> for $DstI<FracDst>
440        where
441            $DstBitsM1: Sub<FracDst>,
442            U1: IsLessOrEqual<Diff<$DstBitsM1, FracDst>, Output = True>,
443        {
444            /// Converts a [`bool`] to a fixed-point number.
445            ///
446            /// This conversion never fails (infallible) and cannot
447            /// lose any fractional bits (lossless).
448            #[inline]
449            fn from(src: bool) -> Self {
450                let unshifted = Self::from_bits(src.into()).to_bits();
451                let shift = FracDst::U32;
452                Self::from_bits(unshifted << shift)
453            }
454        }
455
456        impl<FracDst: $DstLeEqU> LossyFrom<bool> for $DstU<FracDst>
457        where
458            $DstBits: Sub<FracDst>,
459            U1: IsLessOrEqual<Diff<$DstBits, FracDst>, Output = True>,
460        {
461            /// Converts a [`bool`] to a fixed-point number.
462            ///
463            /// This conversion never fails (infallible) and cannot
464            /// lose any fractional bits, so it is actually lossless.
465            #[inline]
466            fn lossy_from(src: bool) -> Self {
467                src.into()
468            }
469        }
470
471        impl<FracDst: $DstLeEqU> LossyFrom<bool> for $DstI<FracDst>
472        where
473            $DstBitsM1: Sub<FracDst>,
474            U1: IsLessOrEqual<Diff<$DstBitsM1, FracDst>, Output = True>,
475        {
476            /// Converts a [`bool`] to a fixed-point number.
477            ///
478            /// This conversion never fails (infallible) and cannot
479            /// lose any fractional bits, so it is actually lossless.
480            #[inline]
481            fn lossy_from(src: bool) -> Self {
482                src.into()
483            }
484        }
485    };
486}
487
488bool_to_fixed! { FixedU8, FixedI8, U8, U7, LeEqU8 }
489bool_to_fixed! { FixedU16, FixedI16, U16, U15, LeEqU16 }
490bool_to_fixed! { FixedU32, FixedI32, U32, U31, LeEqU32 }
491bool_to_fixed! { FixedU64, FixedI64, U64, U63, LeEqU64 }
492bool_to_fixed! { FixedU128, FixedI128, U128, U127, LeEqU128 }
493
494macro_rules! fixed_to_int {
495    (($SrcU:ident, $SrcI:ident) -> ($DstU:ident, $DstI:ident)) => {
496        impl From<$SrcU<U0>> for $DstU {
497            /// Converts a fixed-point number with no fractional bits to an integer.
498            ///
499            /// This conversion never fails (infallible) and cannot
500            /// lose any fractional bits (lossless).
501            #[inline]
502            fn from(src: $SrcU<U0>) -> Self {
503                src.to_bits().into()
504            }
505        }
506
507        impl From<$SrcI<U0>> for $DstI {
508            /// Converts a fixed-point number with no fractional bits to an integer.
509            ///
510            /// This conversion never fails (infallible) and cannot
511            /// lose any fractional bits (lossless).
512            #[inline]
513            fn from(src: $SrcI<U0>) -> Self {
514                src.to_bits().into()
515            }
516        }
517    };
518    (($SrcU:ident, $SrcI:ident) -> wider ($DstU:ident, $DstI:ident)) => {
519        fixed_to_int! { ($SrcU, $SrcI) -> ($DstU, $DstI) }
520
521        impl From<$SrcU<U0>> for $DstI {
522            /// Converts a fixed-point number with no fractional bits to an integer.
523            ///
524            /// This conversion never fails (infallible) and cannot
525            /// lose any fractional bits (lossless).
526            #[inline]
527            fn from(src: $SrcU<U0>) -> Self {
528                src.to_bits().into()
529            }
530        }
531    };
532}
533
534fixed_to_int! { (FixedU8, FixedI8) -> (u8, i8) }
535fixed_to_int! { (FixedU8, FixedI8) -> wider (u16, i16) }
536fixed_to_int! { (FixedU8, FixedI8) -> wider (u32, i32) }
537fixed_to_int! { (FixedU8, FixedI8) -> wider (u64, i64) }
538fixed_to_int! { (FixedU8, FixedI8) -> wider (u128, i128) }
539fixed_to_int! { (FixedU8, FixedI8) -> wider (usize, isize) }
540
541fixed_to_int! { (FixedU16, FixedI16) -> (u16, i16) }
542fixed_to_int! { (FixedU16, FixedI16) -> wider (u32, i32) }
543fixed_to_int! { (FixedU16, FixedI16) -> wider (u64, i64) }
544fixed_to_int! { (FixedU16, FixedI16) -> wider (u128, i128) }
545fixed_to_int! { (FixedU16, FixedI16) -> (usize, isize) }
546
547fixed_to_int! { (FixedU32, FixedI32) -> (u32, i32) }
548fixed_to_int! { (FixedU32, FixedI32) -> wider (u64, i64) }
549fixed_to_int! { (FixedU32, FixedI32) -> wider (u128, i128) }
550
551fixed_to_int! { (FixedU64, FixedI64) -> (u64, i64) }
552fixed_to_int! { (FixedU64, FixedI64) -> wider (u128, i128) }
553
554fixed_to_int! { (FixedU128, FixedI128) -> (u128, i128) }
555
556macro_rules! fixed_to_int_lossless {
557    ($Src:ty, $Dst:ident) => {
558        impl LosslessTryFrom<$Src> for $Dst {
559            /// Converts a fixed-point number to an integer.
560            ///
561            /// This conversion may fail (fallible) but cannot lose
562            /// any fractional bits (lossless).
563            #[inline]
564            fn lossless_try_from(src: $Src) -> Option<Self> {
565                $Dst::checked_from_fixed(src)
566            }
567        }
568    };
569
570    ($Src:ty) => {
571        fixed_to_int_lossless! { $Src, i8 }
572        fixed_to_int_lossless! { $Src, i16 }
573        fixed_to_int_lossless! { $Src, i32 }
574        fixed_to_int_lossless! { $Src, i64 }
575        fixed_to_int_lossless! { $Src, i128 }
576        fixed_to_int_lossless! { $Src, isize }
577        fixed_to_int_lossless! { $Src, u8 }
578        fixed_to_int_lossless! { $Src, u16 }
579        fixed_to_int_lossless! { $Src, u32 }
580        fixed_to_int_lossless! { $Src, u64 }
581        fixed_to_int_lossless! { $Src, u128 }
582        fixed_to_int_lossless! { $Src, usize }
583    };
584}
585
586fixed_to_int_lossless! { FixedI8<U0>}
587fixed_to_int_lossless! { FixedI16<U0>}
588fixed_to_int_lossless! { FixedI32<U0>}
589fixed_to_int_lossless! { FixedI64<U0>}
590fixed_to_int_lossless! { FixedI128<U0>}
591fixed_to_int_lossless! { FixedU8<U0>}
592fixed_to_int_lossless! { FixedU16<U0>}
593fixed_to_int_lossless! { FixedU32<U0>}
594fixed_to_int_lossless! { FixedU64<U0>}
595fixed_to_int_lossless! { FixedU128<U0>}
596
597macro_rules! fixed_to_int_lossy {
598    (
599        ($SrcU:ident, $SrcI:ident, $SrcBits:ident, $SrcLeEqU:ident) ->
600            ($DstU:ident, $DstI:ident, $DstBits:ident, $DstBitsM1:ident, $DstLeEqU:ident)
601    ) => {
602        impl<FracSrc: $SrcLeEqU> LossyFrom<$SrcU<FracSrc>> for $DstU
603        where
604            $SrcBits: Sub<FracSrc>,
605            Diff<$SrcBits, FracSrc>: IsLessOrEqual<$DstBits, Output = True>,
606        {
607            /// Converts a fixed-point number to an integer.
608            ///
609            /// This conversion never fails (infallible) but may lose
610            /// precision (lossy). Any fractional bits in the source
611            /// are discarded, which rounds towards &minus;∞.
612            #[inline]
613            fn lossy_from(src: $SrcU<FracSrc>) -> Self {
614                src.to_num()
615            }
616        }
617
618        impl<FracSrc: $SrcLeEqU> LossyFrom<$SrcI<FracSrc>> for $DstI
619        where
620            $SrcBits: Sub<FracSrc>,
621            Diff<$SrcBits, FracSrc>: IsLessOrEqual<$DstBits, Output = True>,
622        {
623            /// Converts a fixed-point number to an integer.
624            ///
625            /// This conversion never fails (infallible) but may lose
626            /// precision (lossy). Any fractional bits in the source
627            /// are discarded, which rounds towards &minus;∞.
628            #[inline]
629            fn lossy_from(src: $SrcI<FracSrc>) -> Self {
630                src.to_num()
631            }
632        }
633
634        impl<FracSrc: $SrcLeEqU> LossyFrom<$SrcU<FracSrc>> for $DstI
635        where
636            $SrcBits: Sub<FracSrc>,
637            Diff<$SrcBits, FracSrc>: IsLessOrEqual<$DstBitsM1, Output = True>,
638        {
639            /// Converts a fixed-point number to an integer.
640            ///
641            /// This conversion never fails (infallible) but may lose
642            /// precision (lossy). Any fractional bits in the source
643            /// are discarded, which rounds towards &minus;∞.
644            #[inline]
645            fn lossy_from(src: $SrcU<FracSrc>) -> Self {
646                src.to_num()
647            }
648        }
649    };
650    ($SrcU:ident, $SrcI:ident, $SrcBits:ident, $SrcLeEqU:ident) => {
651        fixed_to_int_lossy! {
652            ($SrcU, $SrcI, $SrcBits, $SrcLeEqU) -> (u8, i8, U8, U7, LeEqU8)
653        }
654        fixed_to_int_lossy! {
655            ($SrcU, $SrcI, $SrcBits, $SrcLeEqU) -> (u16, i16, U16, U15, LeEqU16)
656        }
657        fixed_to_int_lossy! {
658            ($SrcU, $SrcI, $SrcBits, $SrcLeEqU) -> (u32, i32, U32, U31, LeEqU32)
659        }
660        fixed_to_int_lossy! {
661            ($SrcU, $SrcI, $SrcBits, $SrcLeEqU) -> (u64, i64, U64, U63, LeEqU64)
662        }
663        fixed_to_int_lossy! {
664            ($SrcU, $SrcI, $SrcBits, $SrcLeEqU) -> (u128, i128, U128, U127, LeEqU128)
665        }
666        fixed_to_int_lossy! {
667            ($SrcU, $SrcI, $SrcBits, $SrcLeEqU) -> (usize, isize, U16, U15, LeEqU16)
668        }
669    };
670}
671
672fixed_to_int_lossy! { FixedU8, FixedI8, U8, LeEqU8 }
673fixed_to_int_lossy! { FixedU16, FixedI16, U16, LeEqU16 }
674fixed_to_int_lossy! { FixedU32, FixedI32, U32, LeEqU32 }
675fixed_to_int_lossy! { FixedU64, FixedI64, U64, LeEqU64 }
676fixed_to_int_lossy! { FixedU128, FixedI128, U128, LeEqU128 }
677
678// f16 has minimum subnormal == 2 ^ -(14 + 10) => 24 fractional bits
679// bf16 has minimum subnormal == 2 ^ -(126 + 7) => 133 fractional bits
680// f32 has minimum subnormal == 2 ^ -(126 + 23) => 149 fractional bits
681// f64 has minimum subnormal == 2 ^ -(1022 + 52) => 1074 fractional bits
682//
683// The only lossless float to fixed possible is from f16 to
684// fixed-point numbers with 24 or more fractional bits.
685macro_rules! float_to_fixed {
686    ($Src:ident, $Dst:ident, $LeEqU:ident) => {
687        impl<Frac: $LeEqU> LosslessTryFrom<$Src> for $Dst<Frac>
688        where
689            U24: IsLessOrEqual<Frac, Output = True>,
690        {
691            /// Converts a floating-point number to a fixed-point
692            /// number.
693            ///
694            /// This conversion may fail (fallible) but cannot lose
695            /// any fractional bits (lossless).
696            #[inline]
697            fn lossless_try_from(src: $Src) -> Option<Self> {
698                src.checked_to_fixed()
699            }
700        }
701    };
702}
703
704float_to_fixed! { half_f16, FixedI32, LeEqU32 }
705float_to_fixed! { half_f16, FixedI64, LeEqU64 }
706float_to_fixed! { half_f16, FixedI128, LeEqU128 }
707
708macro_rules! fixed_to_float {
709    ($Fixed:ident($LeEqU:ident) -> $Float:ident) => {
710        impl<Frac: $LeEqU> From<$Fixed<Frac>> for $Float {
711            /// Converts a fixed-point number to a floating-point number.
712            ///
713            /// This conversion never fails (infallible) and does not
714            /// lose any precision (lossless).
715            #[inline]
716            fn from(src: $Fixed<Frac>) -> $Float {
717                $Float::from_fixed(src)
718            }
719        }
720
721        impl<Frac: $LeEqU> LosslessTryFrom<$Fixed<Frac>> for $Float {
722            /// Converts a fixed-point number to a floating-point number.
723            ///
724            /// This conversion actually never fails (infallible) but
725            /// does not lose any precision (lossless).
726            #[inline]
727            fn lossless_try_from(src: $Fixed<Frac>) -> Option<$Float> {
728                Some($Float::from_fixed(src))
729            }
730        }
731    };
732}
733
734fixed_to_float! { FixedI8(LeEqU8) -> half_f16 }
735fixed_to_float! { FixedU8(LeEqU8) -> half_f16 }
736fixed_to_float! { FixedI8(LeEqU8) -> f32 }
737fixed_to_float! { FixedI16(LeEqU16) -> f32 }
738fixed_to_float! { FixedU8(LeEqU8) -> f32 }
739fixed_to_float! { FixedU16(LeEqU16) -> f32 }
740fixed_to_float! { FixedI8(LeEqU8) -> f64 }
741fixed_to_float! { FixedI16(LeEqU16) -> f64 }
742fixed_to_float! { FixedI32(LeEqU32) -> f64 }
743fixed_to_float! { FixedU8(LeEqU8) -> f64 }
744fixed_to_float! { FixedU16(LeEqU16) -> f64 }
745fixed_to_float! { FixedU32(LeEqU32) -> f64 }
746fixed_to_float! { FixedI8(LeEqU8) -> F128 }
747fixed_to_float! { FixedI16(LeEqU16) -> F128 }
748fixed_to_float! { FixedI32(LeEqU32) -> F128 }
749fixed_to_float! { FixedI64(LeEqU64) -> F128 }
750fixed_to_float! { FixedU8(LeEqU8) -> F128 }
751fixed_to_float! { FixedU16(LeEqU16) -> F128 }
752fixed_to_float! { FixedU32(LeEqU32) -> F128 }
753fixed_to_float! { FixedU64(LeEqU64) -> F128 }
754fixed_to_float! { FixedI8(LeEqU8) -> F128Bits }
755fixed_to_float! { FixedI16(LeEqU16) -> F128Bits }
756fixed_to_float! { FixedI32(LeEqU32) -> F128Bits }
757fixed_to_float! { FixedI64(LeEqU64) -> F128Bits }
758fixed_to_float! { FixedU8(LeEqU8) -> F128Bits }
759fixed_to_float! { FixedU16(LeEqU16) -> F128Bits }
760fixed_to_float! { FixedU32(LeEqU32) -> F128Bits }
761fixed_to_float! { FixedU64(LeEqU64) -> F128Bits }
762
763macro_rules! fixed_to_float_lossy {
764    ($Fixed:ident($LeEqU:ident) -> $Float:ident) => {
765        impl<Frac: $LeEqU> LossyFrom<$Fixed<Frac>> for $Float {
766            /// Converts a fixed-point number to a floating-point number.
767            ///
768            /// This conversion never fails (infallible) but may lose
769            /// precision (lossy). Rounding is to the nearest, with
770            /// ties rounded to even.
771            #[inline]
772            fn lossy_from(src: $Fixed<Frac>) -> $Float {
773                src.to_num()
774            }
775        }
776    };
777    ($Fixed:ident($LeEqU:ident)) => {
778        #[cfg(feature = "nightly-float")]
779        fixed_to_float_lossy! { $Fixed($LeEqU) -> f16 }
780        fixed_to_float_lossy! { $Fixed($LeEqU) -> half_f16 }
781        fixed_to_float_lossy! { $Fixed($LeEqU) -> half_bf16 }
782        fixed_to_float_lossy! { $Fixed($LeEqU) -> f32 }
783        fixed_to_float_lossy! { $Fixed($LeEqU) -> f64 }
784        #[cfg(feature = "nightly-float")]
785        fixed_to_float_lossy! { $Fixed($LeEqU) -> f128 }
786        fixed_to_float_lossy! { $Fixed($LeEqU) -> F128 }
787        fixed_to_float_lossy! { $Fixed($LeEqU) -> F128Bits }
788    };
789}
790
791fixed_to_float_lossy! { FixedI8(LeEqU8) }
792fixed_to_float_lossy! { FixedI16(LeEqU16) }
793fixed_to_float_lossy! { FixedI32(LeEqU32) }
794fixed_to_float_lossy! { FixedI64(LeEqU64) }
795fixed_to_float_lossy! { FixedI128(LeEqU128) }
796fixed_to_float_lossy! { FixedU8(LeEqU8) }
797fixed_to_float_lossy! { FixedU16(LeEqU16) }
798fixed_to_float_lossy! { FixedU32(LeEqU32) }
799fixed_to_float_lossy! { FixedU64(LeEqU64) }
800fixed_to_float_lossy! { FixedU128(LeEqU128) }
801
802macro_rules! int_to_float_lossy_lossless {
803    ($Int:ident -> $($Lossy:ident)*; $($Lossless:ident)*) => {
804        $(
805            impl LossyFrom<$Int> for $Lossy {
806                /// Converts an integer to a floating-point number.
807                ///
808                /// This conversion never fails (infallible) but may
809                /// lose precision (lossy). Rounding is to the
810                /// nearest, with ties rounded to even.
811                #[inline]
812                fn lossy_from(src: $Int) -> $Lossy {
813                    Self::from_fixed(IntFixed(src).fixed())
814                }
815            }
816        )*
817        $(
818            impl LosslessTryFrom<$Int> for $Lossless {
819                /// Converts an integer to a floating-point number.
820                ///
821                /// This conversion actually never fails (infallible)
822                /// and does not lose precision (lossless).
823                #[inline]
824                fn lossless_try_from(src: $Int) -> Option<$Lossless> {
825                    Some(Self::from_fixed(IntFixed(src).fixed()))
826                }
827            }
828
829            impl LossyFrom<$Int> for $Lossless {
830                /// Converts an integer to a floating-point number.
831                ///
832                /// This conversion never fails (infallible) and
833                /// actually does not lose precision (lossless).
834                #[inline]
835                fn lossy_from(src: $Int) -> $Lossless {
836                    Self::from_fixed(IntFixed(src).fixed())
837                }
838            }
839        )*
840    };
841}
842
843int_to_float_lossy_lossless! { i8 -> half_bf16; half_f16 f32 f64 F128 F128Bits }
844int_to_float_lossy_lossless! { i16 -> half_bf16 half_f16; f32 f64 F128 F128Bits }
845int_to_float_lossy_lossless! { i32 -> half_bf16 half_f16 f32; f64 F128 F128Bits }
846int_to_float_lossy_lossless! { i64 -> half_bf16 half_f16 f32 f64; F128 F128Bits }
847int_to_float_lossy_lossless! { i128 -> half_bf16 half_f16 f32 f64 F128 F128Bits; }
848int_to_float_lossy_lossless! { isize -> half_bf16 half_f16 f32 f64 F128 F128Bits; }
849
850int_to_float_lossy_lossless! { u8 -> half_bf16; half_f16 f32 f64 F128 F128Bits }
851int_to_float_lossy_lossless! { u16 -> half_bf16 half_f16; f32 f64 F128 F128Bits }
852int_to_float_lossy_lossless! { u32 -> half_bf16 half_f16 f32; f64 F128 F128Bits }
853int_to_float_lossy_lossless! { u64 -> half_bf16 half_f16 f32 f64; F128 F128Bits }
854int_to_float_lossy_lossless! { u128 -> half_bf16 half_f16 f32 f64 F128 F128Bits; }
855int_to_float_lossy_lossless! { usize -> half_bf16 half_f16 f32 f64 F128 F128Bits; }
856
857macro_rules! into {
858    ($Src:ty: $($Dst:ty),*) => { $(
859        impl LosslessTryFrom<$Src> for $Dst {
860            /// Converts a number.
861            ///
862            /// This conversion actually never fails (infallible) and
863            /// does not lose any precision (lossless).
864            #[inline]
865            fn lossless_try_from(src: $Src) -> Option<Self> {
866                Some(Self::from(src))
867            }
868        }
869
870        impl LossyFrom<$Src> for $Dst {
871            /// Converts a number.
872            ///
873            /// This conversion never fails (infallible) and actually
874            /// does not lose any precision (lossless).
875            #[inline]
876            fn lossy_from(src: $Src) -> Self {
877                Self::from(src)
878            }
879        }
880    )* };
881}
882
883macro_rules! try_into {
884    ($Src:ty: $($Dst:ty),*) => { $(
885        impl LosslessTryFrom<$Src> for $Dst {
886            /// Converts a number.
887            ///
888            /// This conversion may fail (fallible) but does not lose
889            /// any precision (lossless).
890            #[inline]
891            fn lossless_try_from(src: $Src) -> Option<Self> {
892                Self::try_from(src).ok()
893            }
894        }
895    )* };
896}
897
898into! { bool: bool, i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize }
899
900into! { i8: i8, i16, i32, i64, i128, isize }
901try_into! { i8: u8, u16, u32, u64, u128, usize }
902into! { i16: i16, i32, i64, i128, isize }
903try_into! { i16: i8, u8, u16, u32, u64, u128, usize }
904into! { i32: i32, i64, i128 }
905try_into! { i32: i8, i16, isize, u8, u16, u32, u64, u128, usize }
906into! { i64: i64, i128 }
907try_into! { i64: i8, i16, i32, isize, u8, u16, u32, u64, u128, usize }
908into! { i128: i128 }
909try_into! { i128: i8, i16, i32, i64, isize, u8, u16, u32, u64, u128, usize }
910into! { isize: isize }
911try_into! { isize: i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, usize }
912
913into! { u8: i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize }
914try_into! { u8: i8 }
915into! { u16: i32, i64, i128, u16, u32, u64, u128, usize }
916try_into! { u16: i8, i16, isize, u8 }
917into! { u32: i64, i128, u32, u64, u128 }
918try_into! { u32: i8, i16, i32, isize, u8, u16, usize }
919into! { u64: i128, u64, u128 }
920try_into! { u64: i8, i16, i32, i64, isize, u8, u16, u32, usize }
921into! { u128: u128 }
922try_into! { u128: i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, usize }
923into! { usize: usize }
924try_into! { usize: i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128 }
925
926macro_rules! lossy {
927    ($Src:ty: $Dst:ty; $src:ident -> $conv:expr) => {
928        impl LossyFrom<$Src> for $Dst {
929            #[inline]
930            /// Converts a number.
931            ///
932            /// This conversion never fails (infallible) but may lose
933            /// precision (lossy). Rounding is to the nearest, with
934            /// ties rounded to even.
935            fn lossy_from($src: $Src) -> $Dst {
936                $conv
937            }
938        }
939    };
940}
941
942into! { half_f16: half_f16 }
943lossy! { half_f16: half_bf16; src -> half_bf16::from_f32(src.into()) }
944into! { half_f16: f32, f64 }
945
946lossy! { half_bf16: half_f16; src -> half_f16::from_f32(src.into()) }
947into! { half_bf16: half_bf16, f32, f64 }
948
949lossy! { f32: half_f16; src -> half_f16::from_f32(src) }
950lossy! { f32: half_bf16; src -> half_bf16::from_f32(src) }
951into! { f32: f32, f64 }
952
953lossy! { f64: half_f16; src -> half_f16::from_f64(src) }
954lossy! { f64: half_bf16; src -> half_bf16::from_f64(src) }
955lossy! { f64: f32; src -> src as f32 }
956into! { f64: f64 }
957
958#[cfg(feature = "nightly-float")]
959mod nightly_float {
960    use crate::int_helper::IntFixed;
961    use crate::traits::{FromFixed, LosslessTryFrom, LossyFrom, ToFixed};
962    use crate::types::extra::{
963        IsLessOrEqual, LeEqU8, LeEqU16, LeEqU32, LeEqU64, LeEqU128, True, U24,
964    };
965    use crate::{
966        FixedI8, FixedI16, FixedI32, FixedI64, FixedI128, FixedU8, FixedU16, FixedU32, FixedU64,
967    };
968
969    float_to_fixed! { f16, FixedI32, LeEqU32 }
970    float_to_fixed! { f16, FixedI64, LeEqU64 }
971    float_to_fixed! { f16, FixedI128, LeEqU128 }
972
973    fixed_to_float! { FixedI8(LeEqU8) -> f16 }
974    fixed_to_float! { FixedU8(LeEqU8) -> f16 }
975    fixed_to_float! { FixedI8(LeEqU8) -> f128 }
976    fixed_to_float! { FixedI16(LeEqU16) -> f128 }
977    fixed_to_float! { FixedI32(LeEqU32) -> f128 }
978    fixed_to_float! { FixedI64(LeEqU64) -> f128 }
979    fixed_to_float! { FixedU8(LeEqU8) -> f128 }
980    fixed_to_float! { FixedU16(LeEqU16) -> f128 }
981    fixed_to_float! { FixedU32(LeEqU32) -> f128 }
982    fixed_to_float! { FixedU64(LeEqU64) -> f128 }
983
984    int_to_float_lossy_lossless! { i8 -> ; f16 f128 }
985    int_to_float_lossy_lossless! { i16 -> f16; f128 }
986    int_to_float_lossy_lossless! { i32 -> f16; f128 }
987    int_to_float_lossy_lossless! { i64 -> f16; f128 }
988    int_to_float_lossy_lossless! { i128 -> f16 f128; }
989    int_to_float_lossy_lossless! { isize -> f16 f128; }
990
991    int_to_float_lossy_lossless! { u8 -> ; f16 f128 }
992    int_to_float_lossy_lossless! { u16 -> f16; f128 }
993    int_to_float_lossy_lossless! { u32 -> f16; f128 }
994    int_to_float_lossy_lossless! { u64 -> f16; f128 }
995    int_to_float_lossy_lossless! { u128 -> f16 f128; }
996    int_to_float_lossy_lossless! { usize -> f16 f128; }
997
998    // From<f16> not implemented for f32
999    into! { f16: f16, f64, f128 }
1000    into! { f32: f128 }
1001    into! { f64: f128 }
1002    into! { f128: f128 }
1003
1004    lossy! { f32: f16; src -> src as f16 }
1005    lossy! { f64: f16; src -> src as f16 }
1006    lossy! { f128: f16; src -> src as f16 }
1007    lossy! { f128: f32; src -> src as f32 }
1008    lossy! { f128: f64; src -> src as f64 }
1009}
1010
1011/// These are doc tests that should not appear in the docs, but are
1012/// useful as doc tests can check to ensure compilation failure.
1013///
1014/// The first snippet succeeds, and acts as a control.
1015///
1016/// ```rust
1017/// use fixed::traits::{LosslessTryFrom, LossyFrom};
1018/// use fixed::types::*;
1019/// let _ = I8F8::from(I4F4::default());
1020/// let _ = I8F8::from(U7F1::default());
1021/// let _ = U8F8::from(U4F4::default());
1022/// let _ = I8F8::lossless_try_from(U8F8::default());
1023/// let _ = I8F8::lossless_try_from(I56F8::default());
1024/// let _ = U8F8::lossless_try_from(U56F8::default());
1025/// let _ = I8F8::lossy_from(I8F56::default());
1026/// let _ = I8F8::lossy_from(U7F57::default());
1027/// let _ = U8F8::lossy_from(U8F56::default());
1028/// let _ = usize::from(U16F0::default());
1029/// let _ = isize::from(I16F0::default());
1030/// let _ = isize::from(U8F0::default());
1031/// let _ = usize::lossless_try_from(I8F0::default());
1032/// let _ = usize::lossless_try_from(I16F0::default());
1033/// let _ = isize::lossless_try_from(U16F0::default());
1034/// ```
1035///
1036/// The rest of the tests should all fail compilation.
1037///
1038/// Not enough fractional bits.
1039/// ```rust,compile_fail
1040/// use fixed::types::*;
1041/// let _ = I8F8::from(I7F9::default());
1042/// ```
1043/// ```rust,compile_fail
1044/// use fixed::traits::LosslessTryFrom;
1045/// use fixed::types::*;
1046/// let _ = I8F8::lossless_try_from(I7F9::default());
1047/// ```
1048///
1049/// Not enough integer bits.
1050/// ```rust,compile_fail
1051/// use fixed::types::*;
1052/// let _ = I8F8::from(I9F7::default());
1053/// ```
1054/// ```rust,compile_fail
1055/// use fixed::traits::LossyFrom;
1056/// use fixed::types::*;
1057/// let _ = I8F8::lossy_from(I9F7::default());
1058/// ```
1059///
1060/// Not enough integer bits for unsigned to signed.
1061/// ```rust,compile_fail
1062/// use fixed::types::*;
1063/// let _ = I8F8::from(U8F0::default());
1064/// ```
1065/// ```rust,compile_fail
1066/// use fixed::traits::LossyFrom;
1067/// use fixed::types::*;
1068/// let _ = I8F8::lossy_from(U8F0::default());
1069/// ```
1070///
1071/// Not  enough fractional bits.
1072/// ```rust,compile_fail
1073/// use fixed::types::*;
1074/// let _ = U8F8::from(U7F9::default());
1075/// ```
1076/// ```rust,compile_fail
1077/// use fixed::traits::LosslessTryFrom;
1078/// use fixed::types::*;
1079/// let _ = U8F8::lossless_try_from(U7F9::default());
1080/// ```
1081///
1082/// Not enough integer bits.
1083/// ```rust,compile_fail
1084/// use fixed::types::*;
1085/// let _ = U8F8::from(U9F7::default());
1086/// ```
1087/// ```rust,compile_fail
1088/// use fixed::traits::LossyFrom;
1089/// use fixed::types::*;
1090/// let _ = U8F8::lossy_from(U9F7::default());
1091/// ```
1092///
1093/// Signed to unsigned.
1094/// ```rust,compile_fail
1095/// use fixed::types::*;
1096/// let _ = U8F8::from(I4F4::default());
1097/// ```
1098/// ```rust,compile_fail
1099/// use fixed::traits::LossyFrom;
1100/// use fixed::types::*;
1101/// let _ = U8F8::lossy_from(I4F4::default());
1102/// ```
1103///
1104/// Not enough fractional bits.
1105/// ```rust,compile_fail
1106/// use fixed::traits::LosslessTryFrom;
1107/// use fixed::types::*;
1108/// let _ = I8F8::lossless_try_from(I55F9::default());
1109/// ```
1110///
1111/// Not enough integer bits.
1112/// ```rust,compile_fail
1113/// use fixed::traits::LossyFrom;
1114/// use fixed::types::*;
1115/// let _ = I8F8::lossy_from(I9F55::default());
1116/// ```
1117/// ```rust,compile_fail
1118/// use fixed::traits::LossyFrom;
1119/// use fixed::types::*;
1120/// let _ = U8F8::lossy_from(U9F55::default());
1121/// ```
1122///
1123/// Signed to unsigned.
1124/// ```rust,compile_fail
1125/// use fixed::traits::LossyFrom;
1126/// use fixed::types::*;
1127/// let _ = I8F8::lossy_from(U8F56::default());
1128/// ```
1129///
1130/// Not enough fractional bits.
1131/// ```rust,compile_fail
1132/// use fixed::types::*;
1133/// let _ = usize::from(U16F16::default());
1134/// ```
1135/// ```rust,compile_fail
1136/// use fixed::types::*;
1137/// let _ = isize::from(I16F16::default());
1138/// ```
1139///
1140/// usize from i8 or i16.
1141/// ```rust,compile_fail
1142/// use fixed::types::*;
1143/// let _ = usize::from(I8F0::default());
1144/// ```
1145/// ```rust,compile_fail
1146/// use fixed::types::*;
1147/// let _ = usize::from(I16F0::default());
1148/// ```
1149///
1150/// isize form u16.
1151/// ```rust,compile_fail
1152/// use fixed::types::*;
1153/// let _ = isize::from(U16F0::default());
1154/// ```
1155fn _compile_fail_tests() {}
1156
1157#[cfg(test)]
1158mod tests {
1159    use crate::types::*;
1160
1161    #[test]
1162    fn expanding_from_unsigned() {
1163        type L8 = U8F0;
1164        type Ll16 = U16F0;
1165        type Lh16 = U8F8;
1166        type Ll128 = U128F0;
1167        type Lh128 = U8F120;
1168
1169        type H8 = U0F8;
1170        type Hl16 = U8F8;
1171        type Hh16 = U0F16;
1172        type Hl128 = U120F8;
1173        type Hh128 = U0F128;
1174
1175        let vals: &[u8] = &[0x00, 0x7f, 0x80, 0xff];
1176        for &val in vals {
1177            let val16 = u16::from(val);
1178            let val128 = u128::from(val);
1179
1180            let l = L8::from_bits(val);
1181            assert_eq!(l, L8::from(val));
1182            assert_eq!(val, u8::from(l));
1183            assert_eq!(Ll16::from(l), Ll16::from_bits(val16));
1184            assert_eq!(Lh16::from(l), Lh16::from_bits(val16 << 8));
1185            assert_eq!(Ll128::from(l), Ll128::from_bits(val128));
1186            assert_eq!(Lh128::from(l), Lh128::from_bits(val128 << 120));
1187
1188            let h = H8::from_bits(val);
1189            assert_eq!(Hl16::from(h), Hl16::from_bits(val16));
1190            assert_eq!(Hh16::from(h), Hh16::from_bits(val16 << 8));
1191            assert_eq!(Hl128::from(h), Hl128::from_bits(val128));
1192            assert_eq!(Hh128::from(h), Hh128::from_bits(val128 << 120));
1193        }
1194    }
1195
1196    #[test]
1197    fn expanding_from_signed() {
1198        type L8 = I8F0;
1199        type Ll16 = I16F0;
1200        type Lh16 = I8F8;
1201        type Ll128 = I128F0;
1202        type Lh128 = I8F120;
1203
1204        type H8 = I0F8;
1205        type Hl16 = I8F8;
1206        type Hh16 = I0F16;
1207        type Hl128 = I120F8;
1208        type Hh128 = I0F128;
1209
1210        let vals: &[i8] = &[0x00, 0x7f, -0x80, -0x01];
1211        for &val in vals {
1212            let val16 = i16::from(val);
1213            let val128 = i128::from(val);
1214
1215            let l = L8::from_bits(val);
1216            assert_eq!(l, L8::from(val));
1217            assert_eq!(val, i8::from(l));
1218            assert_eq!(Ll16::from(l), Ll16::from_bits(val16));
1219            assert_eq!(Lh16::from(l), Lh16::from_bits(val16 << 8));
1220            assert_eq!(Ll128::from(l), Ll128::from_bits(val128));
1221            assert_eq!(Lh128::from(l), Lh128::from_bits(val128 << 120));
1222
1223            let h = H8::from_bits(val);
1224            assert_eq!(Hl16::from(h), Hl16::from_bits(val16));
1225            assert_eq!(Hh16::from(h), Hh16::from_bits(val16 << 8));
1226            assert_eq!(Hl128::from(h), Hl128::from_bits(val128));
1227            assert_eq!(Hh128::from(h), Hh128::from_bits(val128 << 120));
1228        }
1229    }
1230
1231    #[test]
1232    fn expanding_from_unsigned_to_signed() {
1233        type L8 = U8F0;
1234        type Ll16 = I16F0;
1235        type Lh16 = I9F7;
1236        type Ll128 = I128F0;
1237        type Lh128 = I9F119;
1238
1239        type H8 = U0F8;
1240        type Hl16 = I8F8;
1241        type Hh16 = I1F15;
1242        type Hl128 = I120F8;
1243        type Hh128 = I1F127;
1244
1245        let vals: &[u8] = &[0x00, 0x7f, 0x80, 0xff];
1246        for &val in vals {
1247            let val16 = i16::from(val);
1248            let val128 = i128::from(val);
1249
1250            let l = L8::from_bits(val);
1251            assert_eq!(l, L8::from(val));
1252            assert_eq!(val, u8::from(l));
1253            assert_eq!(Ll16::from(l), Ll16::from_bits(val16));
1254            assert_eq!(Lh16::from(l), Lh16::from_bits(val16 << 7));
1255            assert_eq!(Ll128::from(l), Ll128::from_bits(val128));
1256            assert_eq!(Lh128::from(l), Lh128::from_bits(val128 << 119));
1257
1258            let h = H8::from_bits(val);
1259            assert_eq!(Hl16::from(h), Hl16::from_bits(val16));
1260            assert_eq!(Hh16::from(h), Hh16::from_bits(val16 << 7));
1261            assert_eq!(Hl128::from(h), Hl128::from_bits(val128));
1262            assert_eq!(Hh128::from(h), Hh128::from_bits(val128 << 119));
1263        }
1264    }
1265
1266    #[test]
1267    fn from_bool() {
1268        assert_eq!(I2F6::from(true), 1);
1269        assert_eq!(I2F6::from(false), 0);
1270        assert_eq!(I64F64::from(true), 1);
1271        assert_eq!(U1F127::from(true), 1);
1272    }
1273
1274    #[test]
1275    fn to_size() {
1276        let min_i24 = I24F8::MIN;
1277        let max_i24 = I24F8::MAX;
1278        let max_u24 = U24F8::MAX;
1279        assert_eq!(min_i24.overflowing_to_num::<isize>(), (!0 << 23, false));
1280        assert_eq!(max_i24.overflowing_to_num::<isize>(), (!(!0 << 23), false));
1281        assert_eq!(max_u24.overflowing_to_num::<isize>(), (!(!0 << 24), false));
1282        assert_eq!(min_i24.overflowing_to_num::<usize>(), (!0 << 23, true));
1283        assert_eq!(max_i24.overflowing_to_num::<usize>(), (!(!0 << 23), false));
1284        assert_eq!(max_u24.overflowing_to_num::<usize>(), (!(!0 << 24), false));
1285
1286        let min_i56 = I56F8::MIN;
1287        let max_i56 = I56F8::MAX;
1288        let max_u56 = U56F8::MAX;
1289        #[cfg(target_pointer_width = "32")]
1290        {
1291            assert_eq!(min_i56.overflowing_to_num::<isize>(), (0, true));
1292            assert_eq!(max_i56.overflowing_to_num::<isize>(), (!0, true));
1293            assert_eq!(max_u56.overflowing_to_num::<isize>(), (!0, true));
1294            assert_eq!(min_i56.overflowing_to_num::<usize>(), (0, true));
1295            assert_eq!(max_i56.overflowing_to_num::<usize>(), (!0, true));
1296            assert_eq!(max_u56.overflowing_to_num::<usize>(), (!0, true));
1297        }
1298        #[cfg(target_pointer_width = "64")]
1299        {
1300            assert_eq!(min_i56.overflowing_to_num::<isize>(), (!0 << 55, false));
1301            assert_eq!(max_i56.overflowing_to_num::<isize>(), (!(!0 << 55), false));
1302            assert_eq!(max_u56.overflowing_to_num::<isize>(), (!(!0 << 56), false));
1303            assert_eq!(min_i56.overflowing_to_num::<usize>(), (!0 << 55, true));
1304            assert_eq!(max_i56.overflowing_to_num::<usize>(), (!(!0 << 55), false));
1305            assert_eq!(max_u56.overflowing_to_num::<usize>(), (!(!0 << 56), false));
1306        }
1307
1308        let min_i120 = I120F8::MIN;
1309        let max_i120 = I120F8::MAX;
1310        let max_u120 = U120F8::MAX;
1311        assert_eq!(min_i120.overflowing_to_num::<isize>(), (0, true));
1312        assert_eq!(max_i120.overflowing_to_num::<isize>(), (!0, true));
1313        assert_eq!(max_u120.overflowing_to_num::<isize>(), (!0, true));
1314        assert_eq!(min_i120.overflowing_to_num::<usize>(), (0, true));
1315        assert_eq!(max_i120.overflowing_to_num::<usize>(), (!0, true));
1316        assert_eq!(max_u120.overflowing_to_num::<usize>(), (!0, true));
1317    }
1318
1319    #[test]
1320    fn signed_from_float() {
1321        type Fix = I4F4;
1322        // 1.1 -> 0001.1000
1323        assert_eq!(Fix::from_num(3.0 / 2.0), Fix::from_bits(24));
1324        // 0.11 -> 0000.1100
1325        assert_eq!(Fix::from_num(3.0 / 4.0), Fix::from_bits(12));
1326        // 0.011 -> 0000.0110
1327        assert_eq!(Fix::from_num(3.0 / 8.0), Fix::from_bits(6));
1328        // 0.0011 -> 0000.0011
1329        assert_eq!(Fix::from_num(3.0 / 16.0), Fix::from_bits(3));
1330        // 0.00011 -> 0000.0010 (tie to even)
1331        assert_eq!(Fix::from_num(3.0 / 32.0), Fix::from_bits(2));
1332        // 0.00101 -> 0000.0010 (tie to even)
1333        assert_eq!(Fix::from_num(5.0 / 32.0), Fix::from_bits(2));
1334        // 0.000011 -> 0000.0001 (nearest)
1335        assert_eq!(Fix::from_num(3.0 / 64.0), Fix::DELTA);
1336        // 0.00001 -> 0000.0000 (tie to even)
1337        assert_eq!(Fix::from_num(1.0 / 32.0), Fix::ZERO);
1338
1339        // -1.1 -> -0001.1000
1340        assert_eq!(Fix::from_num(-3.0 / 2.0), Fix::from_bits(-24));
1341        // -0.11 -> -0000.1100
1342        assert_eq!(Fix::from_num(-3.0 / 4.0), Fix::from_bits(-12));
1343        // -0.011 -> -0000.0110
1344        assert_eq!(Fix::from_num(-3.0 / 8.0), Fix::from_bits(-6));
1345        // -0.0011 -> -0000.0011
1346        assert_eq!(Fix::from_num(-3.0 / 16.0), Fix::from_bits(-3));
1347        // -0.00011 -> -0000.0010 (tie to even)
1348        assert_eq!(Fix::from_num(-3.0 / 32.0), Fix::from_bits(-2));
1349        // -0.00101 -> -0000.0010 (tie to even)
1350        assert_eq!(Fix::from_num(-5.0 / 32.0), Fix::from_bits(-2));
1351        // -0.000011 -> -0000.0001 (nearest)
1352        assert_eq!(Fix::from_num(-3.0 / 64.0), Fix::from_bits(-1));
1353        // -0.00001 -> 0000.0000 (tie to even)
1354        assert_eq!(Fix::from_num(-1.0 / 32.0), Fix::ZERO);
1355
1356        // 111.1111 -> 111.1111
1357        assert_eq!(Fix::from_num(127.0 / 16.0), Fix::from_bits(127));
1358        // 111.11111 -> 1000.0000, too large (tie to even)
1359        assert_eq!(
1360            Fix::overflowing_from_num(255.0 / 32.0),
1361            (Fix::from_bits(-128), true)
1362        );
1363
1364        // -111.1111 -> -111.1111
1365        assert_eq!(Fix::from_num(-127.0 / 16.0), Fix::from_bits(-127));
1366        // -111.11111 -> -1000.0000 (tie to even)
1367        assert_eq!(Fix::from_num(-255.0 / 32.0), Fix::from_bits(-128));
1368        // -1000.00001 -> -1000.0000 (tie to even)
1369        assert_eq!(Fix::from_num(-257.0 / 32.0), Fix::from_bits(-128));
1370        // -1000.0001 -> too small
1371        assert_eq!(
1372            Fix::overflowing_from_num(-129.0 / 16.0),
1373            (Fix::from_bits(127), true)
1374        );
1375    }
1376
1377    #[test]
1378    fn unsigned_from_num() {
1379        type Fix = U4F4;
1380        // 1.1 -> 0001.1000
1381        assert_eq!(Fix::from_num(3.0 / 2.0), Fix::from_bits(24));
1382        // 0.11 -> 0000.1100
1383        assert_eq!(Fix::from_num(3.0 / 4.0), Fix::from_bits(12));
1384        // 0.011 -> 0000.0110
1385        assert_eq!(Fix::from_num(3.0 / 8.0), Fix::from_bits(6));
1386        // 0.0011 -> 0000.0011
1387        assert_eq!(Fix::from_num(3.0 / 16.0), Fix::from_bits(3));
1388        // 0.00011 -> 0000.0010 (tie to even)
1389        assert_eq!(Fix::from_num(3.0 / 32.0), Fix::from_bits(2));
1390        // 0.00101 -> 0000.0010 (tie to even)
1391        assert_eq!(Fix::from_num(5.0 / 32.0), Fix::from_bits(2));
1392        // 0.000011 -> 0000.0001 (nearest)
1393        assert_eq!(Fix::from_num(3.0 / 64.0), Fix::DELTA);
1394        // 0.00001 -> 0000.0000 (tie to even)
1395        assert_eq!(Fix::from_num(1.0 / 32.0), Fix::ZERO);
1396        // -0.00001 -> 0000.0000 (tie to even)
1397        assert_eq!(Fix::from_num(-1.0 / 32.0), Fix::ZERO);
1398        // -0.0001 -> too small
1399        assert_eq!(
1400            Fix::overflowing_from_num(-1.0 / 16.0),
1401            (Fix::from_bits(255), true)
1402        );
1403
1404        // 1111.1111 -> 1111.1111
1405        assert_eq!(Fix::from_num(255.0 / 16.0), Fix::from_bits(255));
1406        // 1111.11111 -> too large (tie to even)
1407        assert_eq!(Fix::overflowing_from_num(511.0 / 32.0), (Fix::ZERO, true));
1408    }
1409
1410    #[test]
1411    fn to_f16() {
1412        use half::f16 as half_f16;
1413        for u in 0x00..=0xff {
1414            let fu = U1F7::from_bits(u);
1415            assert_eq!(
1416                fu.to_num::<half_f16>(),
1417                half_f16::from_f32(f32::from(u) / 128.0)
1418            );
1419            let i = u as i8;
1420            let fi = I1F7::from_bits(i);
1421            assert_eq!(
1422                fi.to_num::<half_f16>(),
1423                half_f16::from_f32(f32::from(i) / 128.0)
1424            );
1425
1426            for hi in &[
1427                0u32,
1428                0x0000_0100,
1429                0x7fff_ff00,
1430                0x8000_0000,
1431                0x8100_0000,
1432                0xffff_fe00,
1433                0xffff_ff00,
1434            ] {
1435                let uu = *hi | u32::from(u);
1436                let fuu = U25F7::from_bits(uu);
1437                assert_eq!(
1438                    fuu.to_num::<half_f16>(),
1439                    half_f16::from_f32(uu as f32 / 128.0)
1440                );
1441                let ii = uu as i32;
1442                let fii = I25F7::from_bits(ii);
1443                assert_eq!(
1444                    fii.to_num::<half_f16>(),
1445                    half_f16::from_f32(ii as f32 / 128.0)
1446                );
1447            }
1448
1449            for hi in &[
1450                0u128,
1451                0x0000_0000_0000_0000_0000_0000_0000_0100,
1452                0x7fff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
1453                0x8000_0000_0000_0000_0000_0000_0000_0000,
1454                0x8100_0000_0000_0000_0000_0000_0000_0000,
1455                0xffff_ffff_ffff_ffff_ffff_ffff_ffff_fe00,
1456                0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
1457            ] {
1458                let uu = *hi | u128::from(u);
1459                let fuu = U121F7::from_bits(uu);
1460                assert_eq!(
1461                    fuu.to_num::<half_f16>(),
1462                    half_f16::from_f64(uu as f64 / 128.0)
1463                );
1464                let ii = uu as i128;
1465                let fii = I121F7::from_bits(ii);
1466                assert_eq!(
1467                    fii.to_num::<half_f16>(),
1468                    half_f16::from_f64(ii as f64 / 128.0)
1469                );
1470            }
1471        }
1472    }
1473
1474    #[test]
1475    fn to_half_bf16() {
1476        use half::bf16 as half_bf16;
1477        for u in 0x00..=0xff {
1478            let fu = U1F7::from_bits(u);
1479            assert_eq!(
1480                fu.to_num::<half_bf16>(),
1481                half_bf16::from_f32(f32::from(u) / 128.0)
1482            );
1483            let i = u as i8;
1484            let fi = I1F7::from_bits(i);
1485            assert_eq!(
1486                fi.to_num::<half_bf16>(),
1487                half_bf16::from_f32(f32::from(i) / 128.0)
1488            );
1489
1490            for hi in &[
1491                0u32,
1492                0x0000_0100,
1493                0x7fff_ff00,
1494                0x8000_0000,
1495                0x8100_0000,
1496                0xffff_fe00,
1497                0xffff_ff00,
1498            ] {
1499                let uu = *hi | u32::from(u);
1500                let fuu = U25F7::from_bits(uu);
1501                assert_eq!(
1502                    fuu.to_num::<half_bf16>(),
1503                    half_bf16::from_f32(uu as f32 / 128.0)
1504                );
1505                let ii = uu as i32;
1506                let fii = I25F7::from_bits(ii);
1507                assert_eq!(
1508                    fii.to_num::<half_bf16>(),
1509                    half_bf16::from_f32(ii as f32 / 128.0)
1510                );
1511            }
1512
1513            for hi in &[
1514                0u128,
1515                0x0000_0000_0000_0000_0000_0000_0000_0100,
1516                0x7fff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
1517                0x8000_0000_0000_0000_0000_0000_0000_0000,
1518                0x8100_0000_0000_0000_0000_0000_0000_0000,
1519                0xffff_ffff_ffff_ffff_ffff_ffff_ffff_fe00,
1520                0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
1521            ] {
1522                let uu = *hi | u128::from(u);
1523                let fuu = U121F7::from_bits(uu);
1524                assert_eq!(
1525                    fuu.to_num::<half_bf16>(),
1526                    half_bf16::from_f64(uu as f64 / 128.0)
1527                );
1528                let ii = uu as i128;
1529                let fii = I121F7::from_bits(ii);
1530                assert_eq!(
1531                    fii.to_num::<half_bf16>(),
1532                    half_bf16::from_f64(ii as f64 / 128.0)
1533                );
1534            }
1535        }
1536    }
1537
1538    #[test]
1539    fn to_f32() {
1540        for u in 0x00..=0xff {
1541            let fu = U1F7::from_bits(u);
1542            assert_eq!(fu.to_num::<f32>(), f32::from(u) / 128.0);
1543            let i = u as i8;
1544            let fi = I1F7::from_bits(i);
1545            assert_eq!(fi.to_num::<f32>(), f32::from(i) / 128.0);
1546
1547            for hi in &[
1548                0u32,
1549                0x0000_0100,
1550                0x7fff_ff00,
1551                0x8000_0000,
1552                0x8100_0000,
1553                0xffff_fe00,
1554                0xffff_ff00,
1555            ] {
1556                let uu = *hi | u32::from(u);
1557                let fuu = U25F7::from_bits(uu);
1558                assert_eq!(fuu.to_num::<f32>(), uu as f32 / 128.0);
1559                let ii = uu as i32;
1560                let fii = I25F7::from_bits(ii);
1561                assert_eq!(fii.to_num::<f32>(), ii as f32 / 128.0);
1562            }
1563
1564            for hi in &[
1565                0u128,
1566                0x0000_0000_0000_0000_0000_0000_0000_0100,
1567                0x7fff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
1568                0x8000_0000_0000_0000_0000_0000_0000_0000,
1569                0x8100_0000_0000_0000_0000_0000_0000_0000,
1570                0xffff_ffff_ffff_ffff_ffff_ffff_ffff_fe00,
1571                0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
1572            ] {
1573                let uu = *hi | u128::from(u);
1574                let fuu = U121F7::from_bits(uu);
1575                assert_eq!(fuu.to_num::<f32>(), (uu as f64 / 128.0) as f32);
1576                let ii = uu as i128;
1577                let fii = I121F7::from_bits(ii);
1578                assert_eq!(fii.to_num::<f32>(), (ii as f64 / 128.0) as f32);
1579            }
1580        }
1581    }
1582
1583    #[test]
1584    fn to_infinite_f32() {
1585        // too_large is 1.ffff_ffff_ffff... << 127,
1586        // which will be rounded to 1.0 << 128.
1587        let too_large = U128F0::MAX;
1588        assert_eq!(too_large.count_ones(), 128);
1589        assert!(too_large.to_num::<f32>().is_infinite());
1590
1591        // still_too_large is 1.ffff_ff << 127,
1592        // which is exactly midway between 1.0 << 128 (even)
1593        // and the largest normal f32 that is 1.ffff_fe << 127 (odd).
1594        // The tie will be rounded to even, which is to 1.0 << 128.
1595        let still_too_large = too_large << 103u32;
1596        assert_eq!(still_too_large.count_ones(), 25);
1597        assert!(still_too_large.to_num::<f32>().is_infinite());
1598
1599        // not_too_large is 1.ffff_feff_ffff... << 127,
1600        // which will be rounded to 1.ffff_fe << 127.
1601        let not_too_large = still_too_large - U128F0::DELTA;
1602        assert_eq!(not_too_large.count_ones(), 127);
1603        assert!(!not_too_large.to_num::<f32>().is_infinite());
1604
1605        // min_128 is -1.0 << 127.
1606        let min_i128 = I128F0::MIN;
1607        assert_eq!(min_i128.count_ones(), 1);
1608        assert_eq!(min_i128.to_num::<f32>(), -(127f32.exp2()));
1609    }
1610
1611    #[test]
1612    fn to_f64() {
1613        for u in 0x00..=0xff {
1614            let fu = U1F7::from_bits(u);
1615            assert_eq!(fu.to_num::<f64>(), f64::from(u) / 128.0);
1616            let i = u as i8;
1617            let fi = I1F7::from_bits(i);
1618            assert_eq!(fi.to_num::<f64>(), f64::from(i) / 128.0);
1619
1620            for hi in &[
1621                0u64,
1622                0x0000_0000_0000_0100,
1623                0x7fff_ffff_ffff_ff00,
1624                0x8000_0000_0000_0000,
1625                0x8100_0000_0000_0000,
1626                0xffff_ffff_ffff_fe00,
1627                0xffff_ffff_ffff_ff00,
1628            ] {
1629                let uu = *hi | u64::from(u);
1630                let fuu = U57F7::from_bits(uu);
1631                assert_eq!(fuu.to_num::<f64>(), uu as f64 / 128.0);
1632                let ii = uu as i64;
1633                let fii = I57F7::from_bits(ii);
1634                assert_eq!(fii.to_num::<f64>(), ii as f64 / 128.0);
1635            }
1636
1637            for hi in &[
1638                0u128,
1639                0x0000_0000_0000_0000_0000_0000_0000_0100,
1640                0x7fff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
1641                0x8000_0000_0000_0000_0000_0000_0000_0000,
1642                0x8100_0000_0000_0000_0000_0000_0000_0000,
1643                0xffff_ffff_ffff_ffff_ffff_ffff_ffff_fe00,
1644                0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
1645            ] {
1646                let uu = *hi | u128::from(u);
1647                let fuu = U121F7::from_bits(uu);
1648                assert_eq!(fuu.to_num::<f64>(), uu as f64 / 128.0);
1649                let ii = uu as i128;
1650                let fii = I121F7::from_bits(ii);
1651                assert_eq!(fii.to_num::<f64>(), ii as f64 / 128.0);
1652            }
1653        }
1654    }
1655
1656    #[test]
1657    fn to_f128() {
1658        use crate::F128;
1659        // -01.3A -> sign 1, biased exp 3FFF, mantissa 3A00 << 96
1660        assert_eq!(
1661            I8F8::from_bits(-0x013A).to_num::<F128>(),
1662            F128::from_bits(0xBFFF_3A00_u128 << 96)
1663        );
1664        assert_eq!(I8F8::NEG_ONE.to_num::<F128>(), F128::NEG_ONE);
1665        // -0.5 -> sign 1, biased exp 3FFE, mantissa 0
1666        assert_eq!(
1667            I8F8::from_num(-0.5).to_num::<F128>(),
1668            F128::from_bits(0xBFFE_u128 << 112)
1669        );
1670        // -1 >> 128 -> sign 1, biased exp 3F7F, mantissa 0
1671        assert_eq!(
1672            I0F128::from_bits(-1).to_num::<F128>(),
1673            F128::from_bits(0xBF7F_u128 << 112)
1674        );
1675        // 0 -> sign 0, biased exp 0, mantissa 0
1676        assert_eq!(I8F8::ZERO.to_num::<F128>(), F128::from_bits(0));
1677        // 1 >> 128 -> sign 0, biased exp 3F7F, mantissa 0
1678        assert_eq!(
1679            I0F128::DELTA.to_num::<F128>(),
1680            F128::from_bits(0x3F7F_u128 << 112)
1681        );
1682        // 0.5 -> sign 0, biased exp 3FFE, mantissa 0
1683        assert_eq!(
1684            I8F8::from_num(0.5).to_num::<F128>(),
1685            F128::from_bits(0x3FFE_u128 << 112)
1686        );
1687        assert_eq!(I8F8::ONE.to_num::<F128>(), F128::ONE);
1688        // 01.3A -> sign 0, biased exp 3FFF, mantissa 3A00 << 96
1689        assert_eq!(
1690            I8F8::from_bits(0x013A).to_num::<F128>(),
1691            F128::from_bits(0x3FFF_3A00_u128 << 96)
1692        );
1693    }
1694
1695    #[test]
1696    fn to_f128_bits() {
1697        use crate::F128Bits;
1698        // -01.3A -> sign 1, biased exp 3FFF, mantissa 3A00 << 96
1699        assert_eq!(
1700            I8F8::from_bits(-0x013A).to_num::<F128Bits>(),
1701            F128Bits(0xBFFF_3A00_u128 << 96)
1702        );
1703        // -1 -> sign 1, biased exp 3FFF, mantissa 0
1704        assert_eq!(
1705            I8F8::NEG_ONE.to_num::<F128Bits>(),
1706            F128Bits(0xBFFF_u128 << 112)
1707        );
1708        // -0.5 -> sign 1, biased exp 3FFE, mantissa 0
1709        assert_eq!(
1710            I8F8::from_num(-0.5).to_num::<F128Bits>(),
1711            F128Bits(0xBFFE_u128 << 112)
1712        );
1713        // -1 >> 128 -> sign 1, biased exp 3F7F, mantissa 0
1714        assert_eq!(
1715            I0F128::from_bits(-1).to_num::<F128Bits>(),
1716            F128Bits(0xBF7F_u128 << 112)
1717        );
1718        // 0 -> sign 0, biased exp 0, mantissa 0
1719        assert_eq!(I8F8::ZERO.to_num::<F128Bits>(), F128Bits(0));
1720        // 1 >> 128 -> sign 0, biased exp 3F7F, mantissa 0
1721        assert_eq!(
1722            I0F128::DELTA.to_num::<F128Bits>(),
1723            F128Bits(0x3F7F_u128 << 112)
1724        );
1725        // 0.5 -> sign 0, biased exp 3FFE, mantissa 0
1726        assert_eq!(
1727            I8F8::from_num(0.5).to_num::<F128Bits>(),
1728            F128Bits(0x3FFE_u128 << 112)
1729        );
1730        // 1 -> sign 0, biased exp 3FFF, mantissa 0
1731        assert_eq!(I8F8::ONE.to_num::<F128Bits>(), F128Bits(0x3FFF_u128 << 112));
1732        // 01.3A -> sign 0, biased exp 3FFF, mantissa 3A00 << 96
1733        assert_eq!(
1734            I8F8::from_bits(0x013A).to_num::<F128Bits>(),
1735            F128Bits(0x3FFF_3A00_u128 << 96)
1736        );
1737    }
1738
1739    #[test]
1740    fn lossy_f16() {
1741        use crate::traits::LossyFrom;
1742        use half::f16 as half_f16;
1743
1744        assert_eq!(
1745            half_f16::lossy_from(f32::NEG_INFINITY),
1746            half_f16::NEG_INFINITY
1747        );
1748        assert!(half_f16::lossy_from(f32::NAN).is_nan());
1749        assert_eq!(half_f16::lossy_from(1e-37f32), half_f16::ZERO);
1750        // -1.625 << 15 is 1 11110 1010000000 is FA80
1751        assert_eq!(
1752            half_f16::lossy_from(-32768f32 * 1.625),
1753            half_f16::from_bits(0xFA80)
1754        );
1755        assert_eq!(half_f16::lossy_from(32768f32 * 2.), half_f16::INFINITY);
1756        // 0x8020 is 0x1.004 << 15 is 0 11110 0000000001
1757        assert_eq!(
1758            half_f16::lossy_from(f32::from(0x8020u16)),
1759            half_f16::from_bits(0x7801)
1760        );
1761        // 0x8030 is rounded to 0x8040 (ties to even)
1762        assert_eq!(
1763            half_f16::lossy_from(f32::from(0x8030u16)),
1764            half_f16::from_bits(0x7802)
1765        );
1766        // 0x8050 is rounded to 0x8040 (ties to even)
1767        assert_eq!(
1768            half_f16::lossy_from(f32::from(0x8050u16)),
1769            half_f16::from_bits(0x7802)
1770        );
1771        // 1.0 >> 24 is minimum non-zero subnormal 0 0000 0000000001
1772        assert_eq!(
1773            half_f16::lossy_from((-24f32).exp2()),
1774            half_f16::from_bits(0x0001)
1775        );
1776        assert_eq!(
1777            half_f16::lossy_from((-24f32).exp2() * 0.5001),
1778            half_f16::from_bits(0x0001)
1779        );
1780        assert_eq!(half_f16::lossy_from((-24f32).exp2() * 0.5), half_f16::ZERO);
1781
1782        assert_eq!(
1783            half_f16::lossy_from(f64::NEG_INFINITY),
1784            half_f16::NEG_INFINITY
1785        );
1786        assert!(half_f16::lossy_from(f64::NAN).is_nan());
1787        assert_eq!(half_f16::lossy_from(1e-37f64), half_f16::ZERO);
1788        // -1.625 << 15 is 1 11110 1010000000 is FA80
1789        assert_eq!(
1790            half_f16::lossy_from(-32768f64 * 1.625),
1791            half_f16::from_bits(0xFA80)
1792        );
1793        assert_eq!(half_f16::lossy_from(32768f64 * 2.), half_f16::INFINITY);
1794        // 0x8020 is 0x1.004 << 15 is 0 11110 0000000001
1795        assert_eq!(
1796            half_f16::lossy_from(f64::from(0x8020u16)),
1797            half_f16::from_bits(0x7801)
1798        );
1799        // 0x8030 is rounded to 0x8040 (ties to even)
1800        assert_eq!(
1801            half_f16::lossy_from(f64::from(0x8030u16)),
1802            half_f16::from_bits(0x7802)
1803        );
1804        // 0x8050 is rounded to 0x8040 (ties to even)
1805        assert_eq!(
1806            half_f16::lossy_from(f64::from(0x8050u16)),
1807            half_f16::from_bits(0x7802)
1808        );
1809        // 1.0 >> 24 is minimum non-zero subnormal 0 0000 0000000001
1810        assert_eq!(
1811            half_f16::lossy_from((-24f64).exp2()),
1812            half_f16::from_bits(0x0001)
1813        );
1814        assert_eq!(
1815            half_f16::lossy_from((-24f64).exp2() * 0.5001),
1816            half_f16::from_bits(0x0001)
1817        );
1818        assert_eq!(half_f16::lossy_from((-24f32).exp2() * 0.5), half_f16::ZERO);
1819    }
1820
1821    #[test]
1822    fn lossy_half_bf16() {
1823        use crate::traits::LossyFrom;
1824        use half::bf16 as half_bf16;
1825
1826        assert_eq!(
1827            half_bf16::lossy_from(f32::NEG_INFINITY),
1828            half_bf16::NEG_INFINITY
1829        );
1830        assert!(half_bf16::lossy_from(f32::NAN).is_nan());
1831        assert_eq!(
1832            half_bf16::lossy_from(f32::MIN_POSITIVE),
1833            half_bf16::MIN_POSITIVE
1834        );
1835        // -1.625 << 127 is 1 11111110 1010000 is FF50
1836        assert_eq!(
1837            half_bf16::lossy_from(127f32.exp2() * -1.625),
1838            half_bf16::from_bits(0xFF50)
1839        );
1840        // max is rounded up
1841        assert_eq!(half_bf16::lossy_from(f32::MAX), half_bf16::INFINITY);
1842        assert_eq!(
1843            half_bf16::lossy_from(f32::from_bits(0x4175_7FFF)),
1844            half_bf16::from_bits(0x4175)
1845        );
1846        assert_eq!(
1847            half_bf16::lossy_from(f32::from_bits(0x4175_8000)),
1848            half_bf16::from_bits(0x4176)
1849        );
1850        assert_eq!(
1851            half_bf16::lossy_from(f32::from_bits(0x4175_8001)),
1852            half_bf16::from_bits(0x4176)
1853        );
1854        assert_eq!(
1855            half_bf16::lossy_from(f32::from_bits(0x4176_7FFF)),
1856            half_bf16::from_bits(0x4176)
1857        );
1858        assert_eq!(
1859            half_bf16::lossy_from(f32::from_bits(0x4176_8000)),
1860            half_bf16::from_bits(0x4176)
1861        );
1862        assert_eq!(
1863            half_bf16::lossy_from(f32::from_bits(0x4176_8001)),
1864            half_bf16::from_bits(0x4177)
1865        );
1866
1867        assert_eq!(
1868            half_bf16::lossy_from(f64::NEG_INFINITY),
1869            half_bf16::NEG_INFINITY
1870        );
1871        assert!(half_bf16::lossy_from(f64::NAN).is_nan());
1872        assert_eq!(half_bf16::lossy_from(1e-100f64), half_bf16::ZERO);
1873        // -1.625 << 127 is 1 11111110 1010000 is FF50
1874        assert_eq!(
1875            half_bf16::lossy_from(127f64.exp2() * -1.625),
1876            half_bf16::from_bits(0xFF50)
1877        );
1878        assert_eq!(half_bf16::lossy_from(128f64.exp2()), half_bf16::INFINITY);
1879        // 1.0 >> 133 is minimum non-zero subnormal 0 0000000 0000001
1880        assert_eq!(
1881            half_bf16::lossy_from((-133f64).exp2()),
1882            half_bf16::from_bits(0x0001)
1883        );
1884        assert_eq!(
1885            half_bf16::lossy_from((-133f64).exp2() * 0.5001),
1886            half_bf16::from_bits(0x0001)
1887        );
1888        assert_eq!(
1889            half_bf16::lossy_from((-133f32).exp2() * 0.5),
1890            half_bf16::ZERO
1891        );
1892    }
1893
1894    #[test]
1895    fn keep_nothing() {
1896        assert_eq!(I32F0::from_num(I0F32::MIN), -1);
1897        assert_eq!(I32F0::from_num(I0F32::MAX), 0);
1898        assert_eq!(I32F0::from_num(U0F32::MIN), 0);
1899        assert_eq!(I32F0::from_num(U0F32::MAX), 0);
1900        assert_eq!(U32F0::checked_from_num(I0F32::MIN), None);
1901        assert_eq!(U32F0::from_num(I0F32::MAX), 0);
1902        assert_eq!(U32F0::from_num(U0F32::MIN), 0);
1903        assert_eq!(U32F0::from_num(U0F32::MAX), 0);
1904
1905        assert_eq!(I0F32::from_num(I32F0::ZERO), 0);
1906        assert_eq!(I0F32::from_num(U32F0::ZERO), 0);
1907        assert_eq!(U0F32::from_num(I32F0::ZERO), 0);
1908        assert_eq!(U0F32::from_num(U32F0::ZERO), 0);
1909
1910        assert_eq!(I128F0::from_num(I0F128::MIN), -1);
1911        assert_eq!(I128F0::from_num(I0F128::MAX), 0);
1912        assert_eq!(I128F0::from_num(U0F128::MIN), 0);
1913        assert_eq!(I128F0::from_num(U0F128::MAX), 0);
1914        assert_eq!(U128F0::checked_from_num(I0F128::MIN), None);
1915        assert_eq!(U128F0::from_num(I0F128::MAX), 0);
1916        assert_eq!(U128F0::from_num(U0F128::MIN), 0);
1917        assert_eq!(U128F0::from_num(U0F128::MAX), 0);
1918
1919        assert_eq!(I0F128::from_num(I128F0::ZERO), 0);
1920        assert_eq!(I0F128::from_num(U128F0::ZERO), 0);
1921        assert_eq!(U0F128::from_num(I128F0::ZERO), 0);
1922        assert_eq!(U0F128::from_num(U128F0::ZERO), 0);
1923    }
1924}