substrate_fixed/
convert.rs

1// Copyright © 2018–2019 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
16use crate::{
17    helpers::IntHelper,
18    traits::LossyFrom,
19    types::extra::{
20        Diff, IsLessOrEqual, LeEqU128, LeEqU16, LeEqU32, LeEqU64, LeEqU8, True, U0, U1, U127, U128,
21        U15, U16, U31, U32, U63, U64, U7, U8,
22    },
23    FixedI128, FixedI16, FixedI32, FixedI64, FixedI8, FixedU128, FixedU16, FixedU32, FixedU64,
24    FixedU8,
25};
26use core::ops::Sub;
27#[cfg(feature = "f16")]
28use half::{bf16, f16};
29
30macro_rules! convert {
31    (
32        ($SrcU:ident, $SrcI:ident, $SrcBits:ident, $SrcLeEqU:ident) ->
33            ($DstU:ident, $DstI:ident, $DstBits:ident, $DstBitsM1:ident, $DstLeEqU:ident)
34    ) => {
35        impl<FracSrc: $SrcLeEqU, FracDst: $DstLeEqU> From<$SrcU<FracSrc>> for $DstU<FracDst>
36        where
37            FracSrc: IsLessOrEqual<FracDst, Output = True>,
38            $SrcBits: Sub<FracSrc>,
39            $DstBits: Sub<FracDst>,
40            Diff<$SrcBits, FracSrc>: IsLessOrEqual<Diff<$DstBits, FracDst>, Output = True>,
41        {
42            /// Converts a fixed-pint number.
43            ///
44            /// This conversion never fails (infallible) and does not
45            /// lose any precision (lossless).
46            #[inline]
47            fn from(src: $SrcU<FracSrc>) -> Self {
48                let unshifted = Self::from_bits(src.to_bits().into()).to_bits();
49                let shift = FracDst::U32 - FracSrc::U32;
50                Self::from_bits(unshifted << shift)
51            }
52        }
53
54        impl<FracSrc: $SrcLeEqU, FracDst: $DstLeEqU> From<$SrcI<FracSrc>> for $DstI<FracDst>
55        where
56            FracSrc: IsLessOrEqual<FracDst, Output = True>,
57            $SrcBits: Sub<FracSrc>,
58            $DstBits: Sub<FracDst>,
59            Diff<$SrcBits, FracSrc>: IsLessOrEqual<Diff<$DstBits, FracDst>, Output = True>,
60        {
61            /// Converts a fixed-pint number.
62            ///
63            /// This conversion never fails (infallible) and does not
64            /// lose any precision (lossless).
65            #[inline]
66            fn from(src: $SrcI<FracSrc>) -> Self {
67                let unshifted = Self::from_bits(src.to_bits().into()).to_bits();
68                let shift = FracDst::U32 - FracSrc::U32;
69                Self::from_bits(unshifted << shift)
70            }
71        }
72
73        impl<FracSrc: $SrcLeEqU, FracDst: $DstLeEqU> From<$SrcU<FracSrc>> for $DstI<FracDst>
74        where
75            FracSrc: IsLessOrEqual<FracDst, Output = True>,
76            $SrcBits: Sub<FracSrc>,
77            $DstBitsM1: Sub<FracDst>,
78            Diff<$SrcBits, FracSrc>: IsLessOrEqual<Diff<$DstBitsM1, FracDst>, Output = True>,
79        {
80            /// Converts a fixed-pint number.
81            ///
82            /// This conversion never fails (infallible) and does not
83            /// lose any precision (lossless).
84            #[inline]
85            fn from(src: $SrcU<FracSrc>) -> Self {
86                let unshifted = Self::from_bits(src.to_bits().into()).to_bits();
87                let shift = FracDst::U32 - FracSrc::U32;
88                Self::from_bits(unshifted << shift)
89            }
90        }
91    };
92}
93
94macro_rules! convert_lossy {
95    (
96        ($SrcU:ident, $SrcI:ident, $SrcBits:ident, $SrcLeEqU:ident) ->
97            ($DstU:ident, $DstI:ident, $DstBits:ident, $DstBitsM1:ident, $DstLeEqU:ident)) => {
98        impl<FracSrc: $SrcLeEqU, FracDst: $DstLeEqU> LossyFrom<$SrcU<FracSrc>> for $DstU<FracDst>
99        where
100            $SrcBits: Sub<FracSrc>,
101            $DstBits: Sub<FracDst>,
102            Diff<$SrcBits, FracSrc>: IsLessOrEqual<Diff<$DstBits, FracDst>, Output = True>,
103        {
104            /// Converts a fixed-pint number.
105            ///
106            /// This conversion never fails (infallible) but may lose
107            /// precision (lossy). Any fractional bits in the source
108            /// that cannot be represented in the destination are
109            /// truncated.
110            #[inline]
111            fn lossy_from(src: $SrcU<FracSrc>) -> Self {
112                src.to_num()
113            }
114        }
115
116        impl<FracSrc: $SrcLeEqU, FracDst: $DstLeEqU> LossyFrom<$SrcI<FracSrc>> for $DstI<FracDst>
117        where
118            $SrcBits: Sub<FracSrc>,
119            $DstBits: Sub<FracDst>,
120            Diff<$SrcBits, FracSrc>: IsLessOrEqual<Diff<$DstBits, FracDst>, Output = True>,
121        {
122            /// Converts a fixed-pint number.
123            ///
124            /// This conversion never fails (infallible) but may lose
125            /// precision (lossy). Any fractional bits in the source
126            /// that cannot be represented in the destination are
127            /// truncated.
128            #[inline]
129            fn lossy_from(src: $SrcI<FracSrc>) -> Self {
130                src.to_num()
131            }
132        }
133
134        impl<FracSrc: $SrcLeEqU, FracDst: $DstLeEqU> LossyFrom<$SrcU<FracSrc>> for $DstI<FracDst>
135        where
136            $SrcBits: Sub<FracSrc>,
137            $DstBitsM1: Sub<FracDst>,
138            Diff<$SrcBits, FracSrc>: IsLessOrEqual<Diff<$DstBitsM1, FracDst>, Output = True>,
139        {
140            /// Converts a fixed-pint number.
141            ///
142            /// This conversion never fails (infallible) but may lose
143            /// precision (lossy). Any fractional bits in the source
144            /// that cannot be represented in the destination are
145            /// truncated.
146            #[inline]
147            fn lossy_from(src: $SrcU<FracSrc>) -> Self {
148                src.to_num()
149            }
150        }
151    };
152    ($SrcU:ident, $SrcI:ident, $SrcBits:ident, $SrcLeEqU:ident) => {
153        convert_lossy! {
154            ($SrcU, $SrcI, $SrcBits, $SrcLeEqU) -> (FixedU8, FixedI8, U8, U7, LeEqU8)
155        }
156        convert_lossy! {
157            ($SrcU, $SrcI, $SrcBits, $SrcLeEqU) -> (FixedU16, FixedI16, U16, U15, LeEqU16)
158        }
159        convert_lossy! {
160            ($SrcU, $SrcI, $SrcBits, $SrcLeEqU) -> (FixedU32, FixedI32, U32, U31, LeEqU32)
161        }
162        convert_lossy! {
163            ($SrcU, $SrcI, $SrcBits, $SrcLeEqU) -> (FixedU64, FixedI64, U64, U63, LeEqU64)
164        }
165        convert_lossy! {
166            ($SrcU, $SrcI, $SrcBits, $SrcLeEqU) -> (FixedU128, FixedI128, U128, U127, LeEqU128)
167        }
168    };
169}
170
171convert! { (FixedU8, FixedI8, U8, LeEqU8) -> (FixedU16, FixedI16, U16, U15, LeEqU16) }
172convert! { (FixedU8, FixedI8, U8, LeEqU8) -> (FixedU32, FixedI32, U32, U31, LeEqU32) }
173convert! { (FixedU8, FixedI8, U8, LeEqU8) -> (FixedU64, FixedI64, U64, U63, LeEqU64) }
174convert! { (FixedU8, FixedI8, U8, LeEqU8) -> (FixedU128, FixedI128, U128, U127, LeEqU128) }
175
176convert! { (FixedU16, FixedI16, U16, LeEqU16) -> (FixedU32, FixedI32, U32, U31, LeEqU32) }
177convert! { (FixedU16, FixedI16, U16, LeEqU16) -> (FixedU64, FixedI64, U64, U63, LeEqU64) }
178convert! { (FixedU16, FixedI16, U16, LeEqU16) -> (FixedU128, FixedI128, U128, U127, LeEqU128) }
179
180convert! { (FixedU32, FixedI32, U32, LeEqU32) -> (FixedU64, FixedI64, U64, U63, LeEqU64) }
181convert! { (FixedU32, FixedI32, U32, LeEqU32) -> (FixedU128, FixedI128, U128, U127, LeEqU128) }
182
183convert! { (FixedU64, FixedI64, U64, LeEqU64) -> (FixedU128, FixedI128, U128, U127, LeEqU128) }
184
185convert_lossy! { FixedU8, FixedI8, U8, LeEqU8 }
186convert_lossy! { FixedU16, FixedI16, U16, LeEqU16 }
187convert_lossy! { FixedU32, FixedI32, U32, LeEqU32 }
188convert_lossy! { FixedU64, FixedI64, U64, LeEqU64 }
189convert_lossy! { FixedU128, FixedI128, U128, LeEqU128 }
190
191macro_rules! lossy {
192    ($Src:ty) => {
193        impl LossyFrom<$Src> for $Src {
194            /// Converts a number.
195            ///
196            /// This conversion never fails (infallible) and does not
197            /// lose any precision, so it is actually lossless.
198            #[inline]
199            fn lossy_from(src: $Src) -> Self {
200                src
201            }
202        }
203    };
204    ($Src:ty: Into $($Dst:ty),*) => { $(
205        impl LossyFrom<$Src> for $Dst {
206            /// Converts a number.
207            ///
208            /// This conversion never fails (infallible) and does not
209            /// lose any precision, so it is actually lossless.
210            #[inline]
211            fn lossy_from(src: $Src) -> Self {
212                src.into()
213            }
214        }
215    )* };
216}
217
218macro_rules! int_to_fixed {
219    (
220        ($SrcU:ident, $SrcI:ident, $SrcBits:ident, $SrcLeEqU:ident) ->
221            ($DstU:ident, $DstI:ident, $DstBits:ident, $DstBitsM1:ident, $DstLeEqU:ident)
222    ) => {
223        impl<FracDst: $DstLeEqU> From<$SrcU> for $DstU<FracDst>
224        where
225            $DstBits: Sub<FracDst>,
226            $SrcBits: IsLessOrEqual<Diff<$DstBits, FracDst>, Output = True>,
227        {
228            /// Converts an integer to a fixed-point number.
229            ///
230            /// This conversion never fails (infallible) and cannot
231            /// lose any fractional bits, so it is actually lossless.
232            #[inline]
233            fn from(src: $SrcU) -> Self {
234                let unshifted = Self::from_bits(src.into()).to_bits();
235                let shift = FracDst::U32;
236                Self::from_bits(unshifted << shift)
237            }
238        }
239
240        impl<FracDst: $DstLeEqU> From<$SrcI> for $DstI<FracDst>
241        where
242            $DstBits: Sub<FracDst>,
243            $SrcBits: IsLessOrEqual<Diff<$DstBits, FracDst>, Output = True>,
244        {
245            /// Converts an integer to a fixed-point number.
246            ///
247            /// This conversion never fails (infallible) and cannot
248            /// lose any fractional bits, so it is actually lossless.
249            #[inline]
250            fn from(src: $SrcI) -> Self {
251                let unshifted = Self::from_bits(src.into()).to_bits();
252                let shift = FracDst::U32;
253                Self::from_bits(unshifted << shift)
254            }
255        }
256
257        impl<FracDst: $DstLeEqU> From<$SrcU> for $DstI<FracDst>
258        where
259            $DstBitsM1: Sub<FracDst>,
260            $SrcBits: IsLessOrEqual<Diff<$DstBitsM1, FracDst>, Output = True>,
261        {
262            /// Converts an integer to a fixed-point number.
263            ///
264            /// This conversion never fails (infallible) and cannot
265            /// lose any fractional bits, so it is actually lossless.
266            #[inline]
267            fn from(src: $SrcU) -> Self {
268                let unshifted = Self::from_bits(src.into()).to_bits();
269                let shift = FracDst::U32;
270                Self::from_bits(unshifted << shift)
271            }
272        }
273
274        impl<FracDst: $DstLeEqU> LossyFrom<$SrcU> for $DstU<FracDst>
275        where
276            $DstBits: Sub<FracDst>,
277            $SrcBits: IsLessOrEqual<Diff<$DstBits, FracDst>, Output = True>,
278        {
279            /// Converts an integer to a fixed-point number.
280            ///
281            /// This conversion never fails (infallible) and cannot
282            /// lose any fractional bits, so it is actually lossless.
283            #[inline]
284            fn lossy_from(src: $SrcU) -> Self {
285                src.into()
286            }
287        }
288
289        impl<FracDst: $DstLeEqU> LossyFrom<$SrcI> for $DstI<FracDst>
290        where
291            $DstBits: Sub<FracDst>,
292            $SrcBits: IsLessOrEqual<Diff<$DstBits, FracDst>, Output = True>,
293        {
294            /// Converts an integer to a fixed-point number.
295            ///
296            /// This conversion never fails (infallible) and cannot
297            /// lose any fractional bits, so it is actually lossless.
298            #[inline]
299            fn lossy_from(src: $SrcI) -> Self {
300                src.into()
301            }
302        }
303
304        impl<FracDst: $DstLeEqU> LossyFrom<$SrcU> for $DstI<FracDst>
305        where
306            $DstBitsM1: Sub<FracDst>,
307            $SrcBits: IsLessOrEqual<Diff<$DstBitsM1, FracDst>, Output = True>,
308        {
309            /// Converts an integer to a fixed-point number.
310            ///
311            /// This conversion never fails (infallible) and cannot
312            /// lose any fractional bits, so it is actually lossless.
313            #[inline]
314            fn lossy_from(src: $SrcU) -> Self {
315                src.into()
316            }
317        }
318    };
319
320    (($SrcU:ident, $SrcI:ident) -> ($DstU:ident, $DstI:ident)) => {
321        impl From<$SrcU> for $DstU<U0> {
322            /// Converts an integer to a fixed-point number.
323            ///
324            /// This conversion never fails (infallible) and cannot
325            /// lose any fractional bits (lossless).
326            #[inline]
327            fn from(src: $SrcU) -> Self {
328                Self::from_bits(src)
329            }
330        }
331
332        impl From<$SrcI> for $DstI<U0> {
333            /// Converts an integer to a fixed-point number.
334            ///
335            /// This conversion never fails (infallible) and cannot
336            /// lose any fractional bits (lossless).
337            #[inline]
338            fn from(src: $SrcI) -> Self {
339                Self::from_bits(src)
340            }
341        }
342
343        lossy! { $SrcU: Into $DstU<U0> }
344        lossy! { $SrcI: Into $DstI<U0> }
345    };
346}
347
348int_to_fixed! { (u8, i8) -> (FixedU8, FixedI8) }
349int_to_fixed! { (u8, i8, U8, LeEqU8) -> (FixedU16, FixedI16, U16, U15, LeEqU16) }
350int_to_fixed! { (u8, i8, U8, LeEqU8) -> (FixedU32, FixedI32, U32, U31, LeEqU32) }
351int_to_fixed! { (u8, i8, U8, LeEqU8) -> (FixedU64, FixedI64, U64, U63, LeEqU64) }
352int_to_fixed! { (u8, i8, U8, LeEqU8) -> (FixedU128, FixedI128, U128, U127, LeEqU128) }
353
354int_to_fixed! { (u16, i16) -> (FixedU16, FixedI16) }
355int_to_fixed! { (u16, i16, U16, LeEqU16) -> (FixedU32, FixedI32, U32, U31, LeEqU32) }
356int_to_fixed! { (u16, i16, U16, LeEqU16) -> (FixedU64, FixedI64, U64, U63, LeEqU64) }
357int_to_fixed! { (u16, i16, U16, LeEqU16) -> (FixedU128, FixedI128, U128, U127, LeEqU128) }
358
359int_to_fixed! { (u32, i32) -> (FixedU32, FixedI32) }
360int_to_fixed! { (u32, i32, U32, LeEqU32) -> (FixedU64, FixedI64, U64, U63, LeEqU64) }
361int_to_fixed! { (u32, i32, U32, LeEqU32) -> (FixedU128, FixedI128, U128, U127, LeEqU128) }
362
363int_to_fixed! { (u64, i64) -> (FixedU64, FixedI64) }
364int_to_fixed! { (u64, i64, U64, LeEqU64) -> (FixedU128, FixedI128, U128, U127, LeEqU128) }
365
366int_to_fixed! { (u128, i128) -> (FixedU128, FixedI128) }
367
368macro_rules! bool_to_fixed {
369    ($DstU:ident, $DstI:ident, $DstBits:ident, $DstBitsM1:ident, $DstLeEqU:ident) => {
370        impl<FracDst: $DstLeEqU> From<bool> for $DstU<FracDst>
371        where
372            $DstBits: Sub<FracDst>,
373            U1: IsLessOrEqual<Diff<$DstBits, FracDst>, Output = True>,
374        {
375            /// Converts a [`bool`] to a fixed-point number.
376            ///
377            /// This conversion never fails (infallible) and cannot
378            /// lose any fractional bits (lossless).
379            ///
380            /// [`bool`]: https://doc.rust-lang.org/nightly/std/primitive.bool.html
381            #[inline]
382            fn from(src: bool) -> Self {
383                let unshifted = Self::from_bits(src.into()).to_bits();
384                let shift = FracDst::U32;
385                Self::from_bits(unshifted << shift)
386            }
387        }
388
389        impl<FracDst: $DstLeEqU> From<bool> for $DstI<FracDst>
390        where
391            $DstBitsM1: Sub<FracDst>,
392            U1: IsLessOrEqual<Diff<$DstBitsM1, FracDst>, Output = True>,
393        {
394            /// Converts a [`bool`] to a fixed-point number.
395            ///
396            /// This conversion never fails (infallible) and cannot
397            /// lose any fractional bits (lossless).
398            ///
399            /// [`bool`]: https://doc.rust-lang.org/nightly/std/primitive.bool.html
400            #[inline]
401            fn from(src: bool) -> Self {
402                let unshifted = Self::from_bits(src.into()).to_bits();
403                let shift = FracDst::U32;
404                Self::from_bits(unshifted << shift)
405            }
406        }
407
408        impl<FracDst: $DstLeEqU> LossyFrom<bool> for $DstU<FracDst>
409        where
410            $DstBits: Sub<FracDst>,
411            U1: IsLessOrEqual<Diff<$DstBits, FracDst>, Output = True>,
412        {
413            /// Converts a [`bool`] to a fixed-point number.
414            ///
415            /// This conversion never fails (infallible) and cannot
416            /// lose any fractional bits, so it is actually lossless.
417            ///
418            /// [`bool`]: https://doc.rust-lang.org/nightly/std/primitive.bool.html
419            #[inline]
420            fn lossy_from(src: bool) -> Self {
421                src.into()
422            }
423        }
424
425        impl<FracDst: $DstLeEqU> LossyFrom<bool> for $DstI<FracDst>
426        where
427            $DstBitsM1: Sub<FracDst>,
428            U1: IsLessOrEqual<Diff<$DstBitsM1, FracDst>, Output = True>,
429        {
430            /// Converts a [`bool`] to a fixed-point number.
431            ///
432            /// This conversion never fails (infallible) and cannot
433            /// lose any fractional bits, so it is actually lossless.
434            ///
435            /// [`bool`]: https://doc.rust-lang.org/nightly/std/primitive.bool.html
436            #[inline]
437            fn lossy_from(src: bool) -> Self {
438                src.into()
439            }
440        }
441    };
442}
443
444bool_to_fixed! { FixedU8, FixedI8, U8, U7, LeEqU8 }
445bool_to_fixed! { FixedU16, FixedI16, U16, U15, LeEqU16 }
446bool_to_fixed! { FixedU32, FixedI32, U32, U31, LeEqU32 }
447bool_to_fixed! { FixedU64, FixedI64, U64, U63, LeEqU64 }
448bool_to_fixed! { FixedU128, FixedI128, U128, U127, LeEqU128 }
449
450macro_rules! fixed_to_int {
451    (($SrcU:ident, $SrcI:ident) -> ($DstU:ident, $DstI:ident)) => {
452        impl From<$SrcU<U0>> for $DstU {
453            /// Converts a fixed-point number with no fractional bits to an integer.
454            ///
455            /// This conversion never fails (infallible) and cannot
456            /// lose any fractional bits (lossless).
457            #[inline]
458            fn from(src: $SrcU<U0>) -> Self {
459                src.to_bits().into()
460            }
461        }
462
463        impl From<$SrcI<U0>> for $DstI {
464            /// Converts a fixed-point number with no fractional bits to an integer.
465            ///
466            /// This conversion never fails (infallible) and cannot
467            /// lose any fractional bits (lossless).
468            #[inline]
469            fn from(src: $SrcI<U0>) -> Self {
470                src.to_bits().into()
471            }
472        }
473    };
474    (($SrcU:ident, $SrcI:ident) -> wider ($DstU:ident, $DstI:ident)) => {
475        fixed_to_int! { ($SrcU, $SrcI) -> ($DstU, $DstI) }
476
477        impl From<$SrcU<U0>> for $DstI {
478            /// Converts a fixed-point number with no fractional bits to an integer.
479            ///
480            /// This conversion never fails (infallible) and cannot
481            /// lose any fractional bits (lossless).
482            #[inline]
483            fn from(src: $SrcU<U0>) -> Self {
484                src.to_bits().into()
485            }
486        }
487    };
488}
489
490fixed_to_int! { (FixedU8, FixedI8) -> (u8, i8) }
491fixed_to_int! { (FixedU8, FixedI8) -> wider (u16, i16) }
492fixed_to_int! { (FixedU8, FixedI8) -> wider (u32, i32) }
493fixed_to_int! { (FixedU8, FixedI8) -> wider (u64, i64) }
494fixed_to_int! { (FixedU8, FixedI8) -> wider (u128, i128) }
495fixed_to_int! { (FixedU8, FixedI8) -> wider (usize, isize) }
496
497fixed_to_int! { (FixedU16, FixedI16) -> (u16, i16) }
498fixed_to_int! { (FixedU16, FixedI16) -> wider (u32, i32) }
499fixed_to_int! { (FixedU16, FixedI16) -> wider (u64, i64) }
500fixed_to_int! { (FixedU16, FixedI16) -> wider (u128, i128) }
501fixed_to_int! { (FixedU16, FixedI16) -> (usize, isize) }
502
503fixed_to_int! { (FixedU32, FixedI32) -> (u32, i32) }
504fixed_to_int! { (FixedU32, FixedI32) -> wider (u64, i64) }
505fixed_to_int! { (FixedU32, FixedI32) -> wider (u128, i128) }
506
507fixed_to_int! { (FixedU64, FixedI64) -> (u64, i64) }
508fixed_to_int! { (FixedU64, FixedI64) -> wider (u128, i128) }
509
510fixed_to_int! { (FixedU128, FixedI128) -> (u128, i128) }
511
512macro_rules! fixed_to_int_lossy {
513    (
514        ($SrcU:ident, $SrcI:ident, $SrcBits:ident, $SrcLeEqU:ident) ->
515            ($DstU:ident, $DstI:ident, $DstBits:ident, $DstBitsM1:ident, $DstLeEqU:ident)
516    ) => {
517        impl<FracSrc: $SrcLeEqU> LossyFrom<$SrcU<FracSrc>> for $DstU
518        where
519            $SrcBits: Sub<FracSrc>,
520            Diff<$SrcBits, FracSrc>: IsLessOrEqual<$DstBits, Output = True>,
521        {
522            /// Converts a fixed-point number to an integer.
523            ///
524            /// This conversion never fails (infallible) but may lose
525            /// precision (lossy). Any fractional bits in the source
526            /// are truncated.
527            #[inline]
528            fn lossy_from(src: $SrcU<FracSrc>) -> Self {
529                src.to_num()
530            }
531        }
532
533        impl<FracSrc: $SrcLeEqU> LossyFrom<$SrcI<FracSrc>> for $DstI
534        where
535            $SrcBits: Sub<FracSrc>,
536            Diff<$SrcBits, FracSrc>: IsLessOrEqual<$DstBits, Output = True>,
537        {
538            /// Converts a fixed-point number to an integer.
539            ///
540            /// This conversion never fails (infallible) but may lose
541            /// precision (lossy). Any fractional bits in the source
542            /// are truncated.
543            #[inline]
544            fn lossy_from(src: $SrcI<FracSrc>) -> Self {
545                src.to_num()
546            }
547        }
548
549        impl<FracSrc: $SrcLeEqU> LossyFrom<$SrcU<FracSrc>> for $DstI
550        where
551            $SrcBits: Sub<FracSrc>,
552            Diff<$SrcBits, FracSrc>: IsLessOrEqual<$DstBitsM1, Output = True>,
553        {
554            /// Converts a fixed-point number to an integer.
555            ///
556            /// This conversion never fails (infallible) but may lose
557            /// precision (lossy). Any fractional bits in the source
558            /// are truncated.
559            #[inline]
560            fn lossy_from(src: $SrcU<FracSrc>) -> Self {
561                src.to_num()
562            }
563        }
564    };
565    ($SrcU:ident, $SrcI:ident, $SrcBits:ident, $SrcLeEqU:ident) => {
566        fixed_to_int_lossy! {
567            ($SrcU, $SrcI, $SrcBits, $SrcLeEqU) -> (u8, i8, U8, U7, LeEqU8)
568        }
569        fixed_to_int_lossy! {
570            ($SrcU, $SrcI, $SrcBits, $SrcLeEqU) -> (u16, i16, U16, U15, LeEqU16)
571        }
572        fixed_to_int_lossy! {
573            ($SrcU, $SrcI, $SrcBits, $SrcLeEqU) -> (u32, i32, U32, U31, LeEqU32)
574        }
575        fixed_to_int_lossy! {
576            ($SrcU, $SrcI, $SrcBits, $SrcLeEqU) -> (u64, i64, U64, U63, LeEqU64)
577        }
578        fixed_to_int_lossy! {
579            ($SrcU, $SrcI, $SrcBits, $SrcLeEqU) -> (u128, i128, U128, U127, LeEqU128)
580        }
581        fixed_to_int_lossy! {
582            ($SrcU, $SrcI, $SrcBits, $SrcLeEqU) -> (usize, isize, U16, U15, LeEqU16)
583        }
584    };
585}
586
587fixed_to_int_lossy! { FixedU8, FixedI8, U8, LeEqU8 }
588fixed_to_int_lossy! { FixedU16, FixedI16, U16, LeEqU16 }
589fixed_to_int_lossy! { FixedU32, FixedI32, U32, LeEqU32 }
590fixed_to_int_lossy! { FixedU64, FixedI64, U64, LeEqU64 }
591fixed_to_int_lossy! { FixedU128, FixedI128, U128, LeEqU128 }
592
593macro_rules! fixed_to_float {
594    ($Fixed:ident($LeEqU:ident) -> $Float:ident) => {
595        impl<Frac: $LeEqU> From<$Fixed<Frac>> for $Float {
596            /// Converts a fixed-point number to a floating-point number.
597            ///
598            /// This conversion never fails (infallible) and does not
599            /// lose any precision (lossless).
600            #[inline]
601            fn from(src: $Fixed<Frac>) -> $Float {
602                src.to_num()
603            }
604        }
605    };
606}
607
608#[cfg(feature = "f16")]
609fixed_to_float! { FixedI8(LeEqU8) -> f16 }
610#[cfg(feature = "f16")]
611fixed_to_float! { FixedU8(LeEqU8) -> f16 }
612fixed_to_float! { FixedI8(LeEqU8) -> f32 }
613fixed_to_float! { FixedI16(LeEqU16) -> f32 }
614fixed_to_float! { FixedU8(LeEqU8) -> f32 }
615fixed_to_float! { FixedU16(LeEqU16) -> f32 }
616fixed_to_float! { FixedI8(LeEqU8) -> f64 }
617fixed_to_float! { FixedI16(LeEqU16) -> f64 }
618fixed_to_float! { FixedI32(LeEqU32) -> f64 }
619fixed_to_float! { FixedU8(LeEqU8) -> f64 }
620fixed_to_float! { FixedU16(LeEqU16) -> f64 }
621fixed_to_float! { FixedU32(LeEqU32) -> f64 }
622
623macro_rules! fixed_to_float_lossy {
624    ($Fixed:ident($LeEqU:ident) -> $Float:ident) => {
625        impl<Frac: $LeEqU> LossyFrom<$Fixed<Frac>> for $Float {
626            /// Converts a fixed-point number to a floating-point number.
627            ///
628            /// This conversion never fails (infallible) but may lose
629            /// precision (lossy). Rounding is to the nearest, with
630            /// ties rounded to even.
631            #[inline]
632            fn lossy_from(src: $Fixed<Frac>) -> $Float {
633                src.to_num()
634            }
635        }
636    };
637    ($Fixed:ident($LeEqU:ident)) => {
638        #[cfg(feature = "f16")]
639        fixed_to_float_lossy! { $Fixed($LeEqU) -> f16 }
640        #[cfg(feature = "f16")]
641        fixed_to_float_lossy! { $Fixed($LeEqU) -> bf16 }
642        fixed_to_float_lossy! { $Fixed($LeEqU) -> f32 }
643        fixed_to_float_lossy! { $Fixed($LeEqU) -> f64 }
644    };
645}
646
647fixed_to_float_lossy! { FixedI8(LeEqU8) }
648fixed_to_float_lossy! { FixedI16(LeEqU16) }
649fixed_to_float_lossy! { FixedI32(LeEqU32) }
650fixed_to_float_lossy! { FixedI64(LeEqU64) }
651fixed_to_float_lossy! { FixedI128(LeEqU128) }
652fixed_to_float_lossy! { FixedU8(LeEqU8) }
653fixed_to_float_lossy! { FixedU16(LeEqU16) }
654fixed_to_float_lossy! { FixedU32(LeEqU32) }
655fixed_to_float_lossy! { FixedU64(LeEqU64) }
656fixed_to_float_lossy! { FixedU128(LeEqU128) }
657
658macro_rules! int_to_float_lossy_lossless {
659    ($Int:ident -> $($Lossy:ident)*; $($Lossless:ident)*) => {
660        $(
661            impl LossyFrom<$Int> for $Lossy {
662                /// Converts an integer to a floating-point number.
663                ///
664                /// This conversion never fails (infallible) but may
665                /// lose precision (lossy). Rounding is to the
666                /// nearest, with ties rounded to even.
667                #[inline]
668                fn lossy_from(src: $Int) -> $Lossy {
669                    src.to_repr_fixed().to_num()
670                }
671            }
672        )*
673        $(
674            impl LossyFrom<$Int> for $Lossless {
675                /// Converts an integer to a floating-point number.
676                ///
677                /// This conversion never fails (infallible) and does
678                /// not lose precision (lossless).
679                #[inline]
680                fn lossy_from(src: $Int) -> $Lossless {
681                    src.to_repr_fixed().to_num()
682                }
683            }
684        )*
685    };
686}
687
688#[cfg(feature = "f16")]
689int_to_float_lossy_lossless! { i8 -> bf16; f16 }
690int_to_float_lossy_lossless! { i8 -> ; f32 f64 }
691#[cfg(feature = "f16")]
692int_to_float_lossy_lossless! { i16 -> bf16 f16; }
693int_to_float_lossy_lossless! { i16 -> ; f32 f64 }
694#[cfg(feature = "f16")]
695int_to_float_lossy_lossless! { i32 -> bf16 f16; }
696int_to_float_lossy_lossless! { i32 -> f32; f64 }
697#[cfg(feature = "f16")]
698int_to_float_lossy_lossless! { i64 -> bf16 f16; }
699int_to_float_lossy_lossless! { i64 -> f32 f64; }
700#[cfg(feature = "f16")]
701int_to_float_lossy_lossless! { i128 -> bf16 f16; }
702int_to_float_lossy_lossless! { i128 -> f32 f64; }
703#[cfg(feature = "f16")]
704int_to_float_lossy_lossless! { isize -> bf16 f16; }
705int_to_float_lossy_lossless! { isize -> f32 f64; }
706
707#[cfg(feature = "f16")]
708int_to_float_lossy_lossless! { u8 -> bf16; f16 }
709int_to_float_lossy_lossless! { u8 -> ; f32 f64 }
710#[cfg(feature = "f16")]
711int_to_float_lossy_lossless! { u16 -> bf16 f16; }
712int_to_float_lossy_lossless! { u16 -> ; f32 f64 }
713#[cfg(feature = "f16")]
714int_to_float_lossy_lossless! { u32 -> bf16 f16; }
715int_to_float_lossy_lossless! { u32 -> f32; f64 }
716#[cfg(feature = "f16")]
717int_to_float_lossy_lossless! { u64 -> bf16 f16; }
718int_to_float_lossy_lossless! { u64 -> f32 f64; }
719#[cfg(feature = "f16")]
720int_to_float_lossy_lossless! { u128 -> bf16 f16; }
721int_to_float_lossy_lossless! { u128 -> f32 f64; }
722#[cfg(feature = "f16")]
723int_to_float_lossy_lossless! { usize -> bf16 f16; }
724int_to_float_lossy_lossless! { usize -> f32 f64; }
725
726lossy! { bool }
727lossy! { bool: Into i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize }
728lossy! { i8 }
729lossy! { i8: Into i16, i32, i64, i128, isize }
730lossy! { i16 }
731lossy! { i16: Into i32, i64, i128, isize }
732lossy! { i32 }
733lossy! { i32: Into i64, i128 }
734lossy! { i64 }
735lossy! { i64: Into i128 }
736lossy! { i128 }
737lossy! { isize }
738lossy! { u8 }
739lossy! { u8: Into i16, i32, i64, i128, isize, u16, u32, u64, u128, usize }
740lossy! { u16 }
741lossy! { u16: Into i32, i64, i128, u32, u64, u128, usize }
742lossy! { u32 }
743lossy! { u32: Into i64, i128, u64, u128 }
744lossy! { u64 }
745lossy! { u64: Into i128, u128 }
746lossy! { u128 }
747lossy! { usize }
748
749#[cfg(feature = "f16")]
750lossy! { f16 }
751#[cfg(feature = "f16")]
752impl LossyFrom<f16> for bf16 {
753    #[inline]
754    /// Converts a number.
755    ///
756    /// This conversion never fails (infallible) but may lose
757    /// precision (lossy). Rounding is to the nearest, with ties
758    /// rounded to even.
759    fn lossy_from(src: f16) -> bf16 {
760        bf16::from_f32(src.into())
761    }
762}
763#[cfg(feature = "f16")]
764lossy! { f16: Into f32 }
765#[cfg(feature = "f16")]
766lossy! { f16: Into f64 }
767
768#[cfg(feature = "f16")]
769impl LossyFrom<bf16> for f16 {
770    #[inline]
771    /// Converts a number.
772    ///
773    /// This conversion never fails (infallible) but may lose
774    /// precision (lossy). Rounding is to the nearest, with ties
775    /// rounded to even.
776    fn lossy_from(src: bf16) -> f16 {
777        f16::from_f32(src.into())
778    }
779}
780#[cfg(feature = "f16")]
781lossy! { bf16 }
782#[cfg(feature = "f16")]
783lossy! { bf16: Into f32 }
784#[cfg(feature = "f16")]
785lossy! { bf16: Into f64 }
786
787#[cfg(feature = "f16")]
788impl LossyFrom<f32> for f16 {
789    #[inline]
790    /// Converts a number.
791    ///
792    /// This conversion never fails (infallible) but may lose
793    /// precision (lossy). Rounding is to the nearest, with ties
794    /// rounded to even.
795    fn lossy_from(src: f32) -> Self {
796        f16::from_f32(src)
797    }
798}
799#[cfg(feature = "f16")]
800impl LossyFrom<f32> for bf16 {
801    #[inline]
802    /// Converts a number.
803    ///
804    /// This conversion never fails (infallible) but may lose
805    /// precision (lossy). Rounding is to the nearest, with ties
806    /// rounded to even.
807    fn lossy_from(src: f32) -> Self {
808        bf16::from_f32(src)
809    }
810}
811lossy! { f32 }
812lossy! { f32: Into f64 }
813
814#[cfg(feature = "f16")]
815impl LossyFrom<f64> for f16 {
816    #[inline]
817    /// Converts a number.
818    ///
819    /// This conversion never fails (infallible) but may lose
820    /// precision (lossy). Rounding is to the nearest, with ties
821    /// rounded to even.
822    fn lossy_from(src: f64) -> Self {
823        f16::from_f64(src)
824    }
825}
826#[cfg(feature = "f16")]
827impl LossyFrom<f64> for bf16 {
828    #[inline]
829    /// Converts a number.
830    ///
831    /// This conversion never fails (infallible) but may lose
832    /// precision (lossy). Rounding is to the nearest, with ties
833    /// rounded to even.
834    fn lossy_from(src: f64) -> Self {
835        bf16::from_f64(src)
836    }
837}
838impl LossyFrom<f64> for f32 {
839    /// Converts a number.
840    ///
841    /// This conversion never fails (infallible) but may lose
842    /// precision (lossy). Rounding is to the nearest, with ties
843    /// rounded to even.
844    #[inline]
845    fn lossy_from(src: f64) -> Self {
846        src as f32
847    }
848}
849lossy! { f64 }
850
851/// These are doc tests that should not appear in the docs, but are
852/// useful as doc tests can check to ensure compilation failure.
853///
854/// The first snippet succeeds, and acts as a control.
855///
856/// ```rust
857/// use substrate_fixed::{traits::LossyFrom, types::*};
858/// let _ = I8F8::from(I4F4::default());
859/// let _ = I8F8::from(U7F1::default());
860/// let _ = U8F8::from(U4F4::default());
861/// let _ = I8F8::lossy_from(I8F56::default());
862/// let _ = I8F8::lossy_from(U7F57::default());
863/// let _ = U8F8::lossy_from(U8F56::default());
864/// let _ = usize::from(U16F0::default());
865/// let _ = isize::from(I16F0::default());
866/// let _ = isize::from(U8F0::default());
867/// ```
868///
869/// The rest of the tests should all fail compilation.
870///
871/// ```compile_fail
872/// use substrate_fixed::types::*;
873/// let _ = I8F8::from(I7F9::default());
874/// ```
875/// ```compile_fail
876/// use substrate_fixed::types::*;
877/// let _ = I8F8::from(I9F7::default());
878/// ```
879///
880/// ```compile_fail
881/// use substrate_fixed::types::*;
882/// let _ = I8F8::from(U8F0::default());
883/// ```
884///
885/// ```compile_fail
886/// use substrate_fixed::types::*;
887/// let _ = U8F8::from(U7F9::default());
888/// ```
889/// ```compile_fail
890/// use substrate_fixed::types::*;
891/// let _ = U8F8::from(U9F7::default());
892/// ```
893/// ```compile_fail
894/// use substrate_fixed::types::*;
895/// let _ = U8F8::from(I4F4::default());
896/// ```
897///
898/// ```compile_fail
899/// use substrate_fixed::{traits::LossyFrom, types::*};
900/// let _ = I8F8::lossy_from(I9F55::default());
901/// ```
902///
903/// ```compile_fail
904/// use substrate_fixed::{traits::LossyFrom, types::*};
905/// let _ = I8F8::lossy_from(U8F56::default());
906/// ```
907///
908/// ```compile_fail
909/// use substrate_fixed::{traits::LossyFrom, types::*};
910/// let _ = U8F8::lossy_from(U9F55::default());
911/// ```
912/// ```compile_fail
913/// use substrate_fixed::{traits::LossyFrom, types::*};
914/// let _ = U8F8::lossy_from(I4F4::default());
915/// ```
916///
917/// ```compile_fail
918/// use substrate_fixed::types::*;
919/// let _ = usize::from(U16F16::default());
920/// ```
921/// ```compile_fail
922/// use substrate_fixed::types::*;
923/// let _ = usize::from(I16F0::default());
924/// ```
925/// ```compile_fail
926/// use substrate_fixed::types::*;
927/// let _ = isize::from(I16F16::default());
928/// ```
929/// ```compile_fail
930/// use substrate_fixed::types::*;
931/// let _ = isize::from(U16F0::default());
932/// ```
933/// ```compile_fail
934/// use substrate_fixed::types::*;
935/// let _ = usize::from(I8F0::default());
936/// ```
937fn _compile_fail_tests() {}
938
939#[cfg(test)]
940#[allow(clippy::float_cmp)]
941mod tests {
942    use crate::types::*;
943
944    #[test]
945    fn expanding_from_unsigned() {
946        type L8 = U8F0;
947        type LL16 = U16F0;
948        type LH16 = U8F8;
949        type LL128 = U128F0;
950        type LH128 = U8F120;
951
952        type H8 = U0F8;
953        type HL16 = U8F8;
954        type HH16 = U0F16;
955        type HL128 = U120F8;
956        type HH128 = U0F128;
957
958        let vals: &[u8] = &[0x00, 0x7f, 0x80, 0xff];
959        for &val in vals {
960            let val16 = u16::from(val);
961            let val128 = u128::from(val);
962
963            let l = L8::from_bits(val);
964            assert_eq!(l, L8::from(val));
965            assert_eq!(val, u8::from(l));
966            assert_eq!(LL16::from(l), LL16::from_bits(val16));
967            assert_eq!(LH16::from(l), LH16::from_bits(val16 << 8));
968            assert_eq!(LL128::from(l), LL128::from_bits(val128));
969            assert_eq!(LH128::from(l), LH128::from_bits(val128 << 120));
970
971            let h = H8::from_bits(val);
972            assert_eq!(HL16::from(h), HL16::from_bits(val16));
973            assert_eq!(HH16::from(h), HH16::from_bits(val16 << 8));
974            assert_eq!(HL128::from(h), HL128::from_bits(val128));
975            assert_eq!(HH128::from(h), HH128::from_bits(val128 << 120));
976        }
977    }
978
979    #[test]
980    fn expanding_from_signed() {
981        type L8 = I8F0;
982        type LL16 = I16F0;
983        type LH16 = I8F8;
984        type LL128 = I128F0;
985        type LH128 = I8F120;
986
987        type H8 = I0F8;
988        type HL16 = I8F8;
989        type HH16 = I0F16;
990        type HL128 = I120F8;
991        type HH128 = I0F128;
992
993        let vals: &[i8] = &[0x00, 0x7f, -0x80, -0x01];
994        for &val in vals {
995            let val16 = i16::from(val);
996            let val128 = i128::from(val);
997
998            let l = L8::from_bits(val);
999            assert_eq!(l, L8::from(val));
1000            assert_eq!(val, i8::from(l));
1001            assert_eq!(LL16::from(l), LL16::from_bits(val16));
1002            assert_eq!(LH16::from(l), LH16::from_bits(val16 << 8));
1003            assert_eq!(LL128::from(l), LL128::from_bits(val128));
1004            assert_eq!(LH128::from(l), LH128::from_bits(val128 << 120));
1005
1006            let h = H8::from_bits(val);
1007            assert_eq!(HL16::from(h), HL16::from_bits(val16));
1008            assert_eq!(HH16::from(h), HH16::from_bits(val16 << 8));
1009            assert_eq!(HL128::from(h), HL128::from_bits(val128));
1010            assert_eq!(HH128::from(h), HH128::from_bits(val128 << 120));
1011        }
1012    }
1013
1014    #[test]
1015    fn expanding_from_unsigned_to_signed() {
1016        type L8 = U8F0;
1017        type LL16 = I16F0;
1018        type LH16 = I9F7;
1019        type LL128 = I128F0;
1020        type LH128 = I9F119;
1021
1022        type H8 = U0F8;
1023        type HL16 = I8F8;
1024        type HH16 = I1F15;
1025        type HL128 = I120F8;
1026        type HH128 = I1F127;
1027
1028        let vals: &[u8] = &[0x00, 0x7f, 0x80, 0xff];
1029        for &val in vals {
1030            let val16 = i16::from(val);
1031            let val128 = i128::from(val);
1032
1033            let l = L8::from_bits(val);
1034            assert_eq!(l, L8::from(val));
1035            assert_eq!(val, u8::from(l));
1036            assert_eq!(LL16::from(l), LL16::from_bits(val16));
1037            assert_eq!(LH16::from(l), LH16::from_bits(val16 << 7));
1038            assert_eq!(LL128::from(l), LL128::from_bits(val128));
1039            assert_eq!(LH128::from(l), LH128::from_bits(val128 << 119));
1040
1041            let h = H8::from_bits(val);
1042            assert_eq!(HL16::from(h), HL16::from_bits(val16));
1043            assert_eq!(HH16::from(h), HH16::from_bits(val16 << 7));
1044            assert_eq!(HL128::from(h), HL128::from_bits(val128));
1045            assert_eq!(HH128::from(h), HH128::from_bits(val128 << 119));
1046        }
1047    }
1048
1049    #[test]
1050    fn from_bool() {
1051        assert_eq!(I2F6::from(true), 1);
1052        assert_eq!(I2F6::from(false), 0);
1053        assert_eq!(I64F64::from(true), 1);
1054        assert_eq!(U1F127::from(true), 1);
1055    }
1056
1057    #[test]
1058    fn to_size() {
1059        let min_i24 = I24F8::min_value();
1060        let max_i24 = I24F8::max_value();
1061        let max_u24 = U24F8::max_value();
1062        assert_eq!(min_i24.overflowing_to_num::<isize>(), (!0 << 23, false));
1063        assert_eq!(max_i24.overflowing_to_num::<isize>(), (!(!0 << 23), false));
1064        assert_eq!(max_u24.overflowing_to_num::<isize>(), (!(!0 << 24), false));
1065        assert_eq!(min_i24.overflowing_to_num::<usize>(), (!0 << 23, true));
1066        assert_eq!(max_i24.overflowing_to_num::<usize>(), (!(!0 << 23), false));
1067        assert_eq!(max_u24.overflowing_to_num::<usize>(), (!(!0 << 24), false));
1068
1069        let min_i56 = I56F8::min_value();
1070        let max_i56 = I56F8::max_value();
1071        let max_u56 = U56F8::max_value();
1072        #[cfg(target_pointer_width = "32")]
1073        {
1074            assert_eq!(min_i56.overflowing_to_num::<isize>(), (0, true));
1075            assert_eq!(max_i56.overflowing_to_num::<isize>(), (!0, true));
1076            assert_eq!(max_u56.overflowing_to_num::<isize>(), (!0, true));
1077            assert_eq!(min_i56.overflowing_to_num::<usize>(), (0, true));
1078            assert_eq!(max_i56.overflowing_to_num::<usize>(), (!0, true));
1079            assert_eq!(max_u56.overflowing_to_num::<usize>(), (!0, true));
1080        }
1081        #[cfg(target_pointer_width = "64")]
1082        {
1083            assert_eq!(min_i56.overflowing_to_num::<isize>(), (!0 << 55, false));
1084            assert_eq!(max_i56.overflowing_to_num::<isize>(), (!(!0 << 55), false));
1085            assert_eq!(max_u56.overflowing_to_num::<isize>(), (!(!0 << 56), false));
1086            assert_eq!(min_i56.overflowing_to_num::<usize>(), (!0 << 55, true));
1087            assert_eq!(max_i56.overflowing_to_num::<usize>(), (!(!0 << 55), false));
1088            assert_eq!(max_u56.overflowing_to_num::<usize>(), (!(!0 << 56), false));
1089        }
1090
1091        let min_i120 = I120F8::min_value();
1092        let max_i120 = I120F8::max_value();
1093        let max_u120 = U120F8::max_value();
1094        assert_eq!(min_i120.overflowing_to_num::<isize>(), (0, true));
1095        assert_eq!(max_i120.overflowing_to_num::<isize>(), (!0, true));
1096        assert_eq!(max_u120.overflowing_to_num::<isize>(), (!0, true));
1097        assert_eq!(min_i120.overflowing_to_num::<usize>(), (0, true));
1098        assert_eq!(max_i120.overflowing_to_num::<usize>(), (!0, true));
1099        assert_eq!(max_u120.overflowing_to_num::<usize>(), (!0, true));
1100    }
1101
1102    #[test]
1103    fn signed_from_float() {
1104        type Fix = I4F4;
1105        // 1.1 -> 0001.1000
1106        assert_eq!(Fix::from_num(3.0 / 2.0), Fix::from_bits(24));
1107        // 0.11 -> 0000.1100
1108        assert_eq!(Fix::from_num(3.0 / 4.0), Fix::from_bits(12));
1109        // 0.011 -> 0000.0110
1110        assert_eq!(Fix::from_num(3.0 / 8.0), Fix::from_bits(6));
1111        // 0.0011 -> 0000.0011
1112        assert_eq!(Fix::from_num(3.0 / 16.0), Fix::from_bits(3));
1113        // 0.00011 -> 0000.0010 (tie to even)
1114        assert_eq!(Fix::from_num(3.0 / 32.0), Fix::from_bits(2));
1115        // 0.00101 -> 0000.0010 (tie to even)
1116        assert_eq!(Fix::from_num(5.0 / 32.0), Fix::from_bits(2));
1117        // 0.000011 -> 0000.0001 (nearest)
1118        assert_eq!(Fix::from_num(3.0 / 64.0), Fix::from_bits(1));
1119        // 0.00001 -> 0000.0000 (tie to even)
1120        assert_eq!(Fix::from_num(1.0 / 32.0), Fix::from_bits(0));
1121
1122        // -1.1 -> -0001.1000
1123        assert_eq!(Fix::from_num(-3.0 / 2.0), Fix::from_bits(-24));
1124        // -0.11 -> -0000.1100
1125        assert_eq!(Fix::from_num(-3.0 / 4.0), Fix::from_bits(-12));
1126        // -0.011 -> -0000.0110
1127        assert_eq!(Fix::from_num(-3.0 / 8.0), Fix::from_bits(-6));
1128        // -0.0011 -> -0000.0011
1129        assert_eq!(Fix::from_num(-3.0 / 16.0), Fix::from_bits(-3));
1130        // -0.00011 -> -0000.0010 (tie to even)
1131        assert_eq!(Fix::from_num(-3.0 / 32.0), Fix::from_bits(-2));
1132        // -0.00101 -> -0000.0010 (tie to even)
1133        assert_eq!(Fix::from_num(-5.0 / 32.0), Fix::from_bits(-2));
1134        // -0.000011 -> -0000.0001 (nearest)
1135        assert_eq!(Fix::from_num(-3.0 / 64.0), Fix::from_bits(-1));
1136        // -0.00001 -> 0000.0000 (tie to even)
1137        assert_eq!(Fix::from_num(-1.0 / 32.0), Fix::from_bits(0));
1138
1139        // 111.1111 -> 111.1111
1140        assert_eq!(Fix::from_num(127.0 / 16.0), Fix::from_bits(127));
1141        // 111.11111 -> 1000.0000, too large (tie to even)
1142        assert_eq!(
1143            Fix::overflowing_from_num(255.0 / 32.0),
1144            (Fix::from_bits(-128), true)
1145        );
1146
1147        // -111.1111 -> -111.1111
1148        assert_eq!(Fix::from_num(-127.0 / 16.0), Fix::from_bits(-127));
1149        // -111.11111 -> -1000.0000 (tie to even)
1150        assert_eq!(Fix::from_num(-255.0 / 32.0), Fix::from_bits(-128));
1151        // -1000.00001 -> -1000.0000 (tie to even)
1152        assert_eq!(Fix::from_num(-257.0 / 32.0), Fix::from_bits(-128));
1153        // -1000.0001 -> too small
1154        assert_eq!(
1155            Fix::overflowing_from_num(-129.0 / 16.0),
1156            (Fix::from_bits(127), true)
1157        );
1158    }
1159
1160    #[test]
1161    fn unsigned_from_num() {
1162        type Fix = U4F4;
1163        // 1.1 -> 0001.1000
1164        assert_eq!(Fix::from_num(3.0 / 2.0), Fix::from_bits(24));
1165        // 0.11 -> 0000.1100
1166        assert_eq!(Fix::from_num(3.0 / 4.0), Fix::from_bits(12));
1167        // 0.011 -> 0000.0110
1168        assert_eq!(Fix::from_num(3.0 / 8.0), Fix::from_bits(6));
1169        // 0.0011 -> 0000.0011
1170        assert_eq!(Fix::from_num(3.0 / 16.0), Fix::from_bits(3));
1171        // 0.00011 -> 0000.0010 (tie to even)
1172        assert_eq!(Fix::from_num(3.0 / 32.0), Fix::from_bits(2));
1173        // 0.00101 -> 0000.0010 (tie to even)
1174        assert_eq!(Fix::from_num(5.0 / 32.0), Fix::from_bits(2));
1175        // 0.000011 -> 0000.0001 (nearest)
1176        assert_eq!(Fix::from_num(3.0 / 64.0), Fix::from_bits(1));
1177        // 0.00001 -> 0000.0000 (tie to even)
1178        assert_eq!(Fix::from_num(1.0 / 32.0), Fix::from_bits(0));
1179        // -0.00001 -> 0000.0000 (tie to even)
1180        assert_eq!(Fix::from_num(-1.0 / 32.0), Fix::from_bits(0));
1181        // -0.0001 -> too small
1182        assert_eq!(
1183            Fix::overflowing_from_num(-1.0 / 16.0),
1184            (Fix::from_bits(255), true)
1185        );
1186
1187        // 1111.1111 -> 1111.1111
1188        assert_eq!(Fix::from_num(255.0 / 16.0), Fix::from_bits(255));
1189        // 1111.11111 -> too large (tie to even)
1190        assert_eq!(
1191            Fix::overflowing_from_num(511.0 / 32.0),
1192            (Fix::from_bits(0), true)
1193        );
1194    }
1195
1196    #[cfg(feature = "f16")]
1197    #[test]
1198    fn to_f16() {
1199        use half::f16;
1200        for u in 0x00..=0xff {
1201            let fu = U1F7::from_bits(u);
1202            assert_eq!(fu.to_num::<f16>(), f16::from_f32(f32::from(u) / 128.0));
1203            let i = u as i8;
1204            let fi = I1F7::from_bits(i);
1205            assert_eq!(fi.to_num::<f16>(), f16::from_f32(f32::from(i) / 128.0));
1206
1207            for hi in &[
1208                0u32,
1209                0x0000_0100,
1210                0x7fff_ff00,
1211                0x8000_0000,
1212                0x8100_0000,
1213                0xffff_fe00,
1214                0xffff_ff00,
1215            ] {
1216                let uu = *hi | u32::from(u);
1217                let fuu = U25F7::from_bits(uu);
1218                assert_eq!(fuu.to_num::<f16>(), f16::from_f32(uu as f32 / 128.0));
1219                let ii = uu as i32;
1220                let fii = I25F7::from_bits(ii);
1221                assert_eq!(fii.to_num::<f16>(), f16::from_f32(ii as f32 / 128.0));
1222            }
1223
1224            for hi in &[
1225                0u128,
1226                0x0000_0000_0000_0000_0000_0000_0000_0100,
1227                0x7fff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
1228                0x8000_0000_0000_0000_0000_0000_0000_0000,
1229                0x8100_0000_0000_0000_0000_0000_0000_0000,
1230                0xffff_ffff_ffff_ffff_ffff_ffff_ffff_fe00,
1231                0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
1232            ] {
1233                let uu = *hi | u128::from(u);
1234                let fuu = U121F7::from_bits(uu);
1235                assert_eq!(fuu.to_num::<f16>(), f16::from_f64(uu as f64 / 128.0));
1236                let ii = uu as i128;
1237                let fii = I121F7::from_bits(ii);
1238                assert_eq!(fii.to_num::<f16>(), f16::from_f64(ii as f64 / 128.0));
1239            }
1240        }
1241    }
1242
1243    #[cfg(feature = "f16")]
1244    #[test]
1245    fn to_bf16() {
1246        use half::bf16;
1247        for u in 0x00..=0xff {
1248            let fu = U1F7::from_bits(u);
1249            assert_eq!(fu.to_num::<bf16>(), bf16::from_f32(f32::from(u) / 128.0));
1250            let i = u as i8;
1251            let fi = I1F7::from_bits(i);
1252            assert_eq!(fi.to_num::<bf16>(), bf16::from_f32(f32::from(i) / 128.0));
1253
1254            for hi in &[
1255                0u32,
1256                0x0000_0100,
1257                0x7fff_ff00,
1258                0x8000_0000,
1259                0x8100_0000,
1260                0xffff_fe00,
1261                0xffff_ff00,
1262            ] {
1263                let uu = *hi | u32::from(u);
1264                let fuu = U25F7::from_bits(uu);
1265                assert_eq!(fuu.to_num::<bf16>(), bf16::from_f32(uu as f32 / 128.0));
1266                let ii = uu as i32;
1267                let fii = I25F7::from_bits(ii);
1268                assert_eq!(fii.to_num::<bf16>(), bf16::from_f32(ii as f32 / 128.0));
1269            }
1270
1271            for hi in &[
1272                0u128,
1273                0x0000_0000_0000_0000_0000_0000_0000_0100,
1274                0x7fff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
1275                0x8000_0000_0000_0000_0000_0000_0000_0000,
1276                0x8100_0000_0000_0000_0000_0000_0000_0000,
1277                0xffff_ffff_ffff_ffff_ffff_ffff_ffff_fe00,
1278                0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
1279            ] {
1280                let uu = *hi | u128::from(u);
1281                let fuu = U121F7::from_bits(uu);
1282                assert_eq!(fuu.to_num::<bf16>(), bf16::from_f64(uu as f64 / 128.0));
1283                let ii = uu as i128;
1284                let fii = I121F7::from_bits(ii);
1285                assert_eq!(fii.to_num::<bf16>(), bf16::from_f64(ii as f64 / 128.0));
1286            }
1287        }
1288    }
1289
1290    #[test]
1291    fn to_f32() {
1292        for u in 0x00..=0xff {
1293            let fu = U1F7::from_bits(u);
1294            assert_eq!(fu.to_num::<f32>(), f32::from(u) / 128.0);
1295            let i = u as i8;
1296            let fi = I1F7::from_bits(i);
1297            assert_eq!(fi.to_num::<f32>(), f32::from(i) / 128.0);
1298
1299            for hi in &[
1300                0u32,
1301                0x0000_0100,
1302                0x7fff_ff00,
1303                0x8000_0000,
1304                0x8100_0000,
1305                0xffff_fe00,
1306                0xffff_ff00,
1307            ] {
1308                let uu = *hi | u32::from(u);
1309                let fuu = U25F7::from_bits(uu);
1310                assert_eq!(fuu.to_num::<f32>(), uu as f32 / 128.0);
1311                let ii = uu as i32;
1312                let fii = I25F7::from_bits(ii);
1313                assert_eq!(fii.to_num::<f32>(), ii as f32 / 128.0);
1314            }
1315
1316            for hi in &[
1317                0u128,
1318                0x0000_0000_0000_0000_0000_0000_0000_0100,
1319                0x7fff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
1320                0x8000_0000_0000_0000_0000_0000_0000_0000,
1321                0x8100_0000_0000_0000_0000_0000_0000_0000,
1322                0xffff_ffff_ffff_ffff_ffff_ffff_ffff_fe00,
1323                0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
1324            ] {
1325                let uu = *hi | u128::from(u);
1326                let fuu = U121F7::from_bits(uu);
1327                assert_eq!(fuu.to_num::<f32>(), (uu as f64 / 128.0) as f32);
1328                let ii = uu as i128;
1329                let fii = I121F7::from_bits(ii);
1330                assert_eq!(fii.to_num::<f32>(), (ii as f64 / 128.0) as f32);
1331            }
1332        }
1333    }
1334
1335    #[test]
1336    fn to_infinite_f32() {
1337        // too_large is 1.ffff_ffff_ffff... << 127,
1338        // which will be rounded to 1.0 << 128.
1339        let too_large = U128F0::max_value();
1340        assert_eq!(too_large.count_ones(), 128);
1341        assert!(too_large.to_num::<f32>().is_infinite());
1342
1343        // still_too_large is 1.ffff_ff << 127,
1344        // which is exactly midway between 1.0 << 128 (even)
1345        // and the largest normal f32 that is 1.ffff_fe << 127 (odd).
1346        // The tie will be rounded to even, which is to 1.0 << 128.
1347        let still_too_large = too_large << 103u32;
1348        assert_eq!(still_too_large.count_ones(), 25);
1349        assert!(still_too_large.to_num::<f32>().is_infinite());
1350
1351        // not_too_large is 1.ffff_feff_ffff... << 127,
1352        // which will be rounded to 1.ffff_fe << 127.
1353        let not_too_large = still_too_large - U128F0::from_bits(1);
1354        assert_eq!(not_too_large.count_ones(), 127);
1355        assert!(!not_too_large.to_num::<f32>().is_infinite());
1356
1357        // min_128 is -1.0 << 127.
1358        let min_i128 = I128F0::min_value();
1359        assert_eq!(min_i128.count_ones(), 1);
1360        assert_eq!(min_i128.to_num::<f32>(), -(127f32.exp2()));
1361    }
1362
1363    #[test]
1364    fn to_f64() {
1365        for u in 0x00..=0xff {
1366            let fu = U1F7::from_bits(u);
1367            assert_eq!(fu.to_num::<f64>(), f64::from(u) / 128.0);
1368            let i = u as i8;
1369            let fi = I1F7::from_bits(i);
1370            assert_eq!(fi.to_num::<f64>(), f64::from(i) / 128.0);
1371
1372            for hi in &[
1373                0u64,
1374                0x0000_0000_0000_0100,
1375                0x7fff_ffff_ffff_ff00,
1376                0x8000_0000_0000_0000,
1377                0x8100_0000_0000_0000,
1378                0xffff_ffff_ffff_fe00,
1379                0xffff_ffff_ffff_ff00,
1380            ] {
1381                let uu = *hi | u64::from(u);
1382                let fuu = U57F7::from_bits(uu);
1383                assert_eq!(fuu.to_num::<f64>(), uu as f64 / 128.0);
1384                let ii = uu as i64;
1385                let fii = I57F7::from_bits(ii);
1386                assert_eq!(fii.to_num::<f64>(), ii as f64 / 128.0);
1387            }
1388
1389            for hi in &[
1390                0u128,
1391                0x0000_0000_0000_0000_0000_0000_0000_0100,
1392                0x7fff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
1393                0x8000_0000_0000_0000_0000_0000_0000_0000,
1394                0x8100_0000_0000_0000_0000_0000_0000_0000,
1395                0xffff_ffff_ffff_ffff_ffff_ffff_ffff_fe00,
1396                0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
1397            ] {
1398                let uu = *hi | u128::from(u);
1399                let fuu = U121F7::from_bits(uu);
1400                assert_eq!(fuu.to_num::<f64>(), uu as f64 / 128.0);
1401                let ii = uu as i128;
1402                let fii = I121F7::from_bits(ii);
1403                assert_eq!(fii.to_num::<f64>(), ii as f64 / 128.0);
1404            }
1405        }
1406    }
1407
1408    #[cfg(feature = "f16")]
1409    #[test]
1410    fn lossy_f16() {
1411        use crate::traits::LossyFrom;
1412        use core::{f32, f64};
1413        use half::f16;
1414
1415        assert_eq!(f16::lossy_from(f32::NEG_INFINITY), f16::NEG_INFINITY);
1416        assert!(f16::lossy_from(f32::NAN).is_nan());
1417        assert_eq!(f16::lossy_from(1e-37f32), f16::from_bits(0));
1418        // -1.625 << 15 is 1 11110 1010000000 is FA80
1419        assert_eq!(f16::lossy_from(-32768f32 * 1.625), f16::from_bits(0xFA80));
1420        assert_eq!(f16::lossy_from(32768f32 * 2.), f16::INFINITY);
1421        // 0x8020 is 0x1.004 << 15 is 0 11110 0000000001
1422        assert_eq!(
1423            f16::lossy_from(f32::from(0x8020u16)),
1424            f16::from_bits(0x7801)
1425        );
1426        // 0x8030 is rounded to 0x8040 (ties to even)
1427        assert_eq!(
1428            f16::lossy_from(f32::from(0x8030u16)),
1429            f16::from_bits(0x7802)
1430        );
1431        // 0x8050 is rounded to 0x8040 (ties to even)
1432        assert_eq!(
1433            f16::lossy_from(f32::from(0x8050u16)),
1434            f16::from_bits(0x7802)
1435        );
1436        // 1.0 >> 24 is minimum non-zero subnormal 0 0000 0000000001
1437        assert_eq!(f16::lossy_from((-24f32).exp2()), f16::from_bits(0x0001));
1438        assert_eq!(
1439            f16::lossy_from((-24f32).exp2() * 0.5001),
1440            f16::from_bits(0x0001)
1441        );
1442        assert_eq!(f16::lossy_from((-24f32).exp2() * 0.5), f16::from_bits(0));
1443
1444        assert_eq!(f16::lossy_from(f64::NEG_INFINITY), f16::NEG_INFINITY);
1445        assert!(f16::lossy_from(f64::NAN).is_nan());
1446        assert_eq!(f16::lossy_from(1e-37f64), f16::from_bits(0));
1447        // -1.625 << 15 is 1 11110 1010000000 is FA80
1448        assert_eq!(f16::lossy_from(-32768f64 * 1.625), f16::from_bits(0xFA80));
1449        assert_eq!(f16::lossy_from(32768f64 * 2.), f16::INFINITY);
1450        // 0x8020 is 0x1.004 << 15 is 0 11110 0000000001
1451        assert_eq!(
1452            f16::lossy_from(f64::from(0x8020u16)),
1453            f16::from_bits(0x7801)
1454        );
1455        // 0x8030 is rounded to 0x8040 (ties to even)
1456        assert_eq!(
1457            f16::lossy_from(f64::from(0x8030u16)),
1458            f16::from_bits(0x7802)
1459        );
1460        // 0x8050 is rounded to 0x8040 (ties to even)
1461        assert_eq!(
1462            f16::lossy_from(f64::from(0x8050u16)),
1463            f16::from_bits(0x7802)
1464        );
1465        // 1.0 >> 24 is minimum non-zero subnormal 0 0000 0000000001
1466        assert_eq!(f16::lossy_from((-24f64).exp2()), f16::from_bits(0x0001));
1467        assert_eq!(
1468            f16::lossy_from((-24f64).exp2() * 0.5001),
1469            f16::from_bits(0x0001)
1470        );
1471        assert_eq!(f16::lossy_from((-24f32).exp2() * 0.5), f16::from_bits(0));
1472    }
1473
1474    #[cfg(feature = "f16")]
1475    #[test]
1476    fn lossy_bf16() {
1477        use crate::traits::LossyFrom;
1478        use core::{f32, f64};
1479        use half::bf16;
1480
1481        assert_eq!(bf16::lossy_from(f32::NEG_INFINITY), bf16::NEG_INFINITY);
1482        assert!(bf16::lossy_from(f32::NAN).is_nan());
1483        assert_eq!(bf16::lossy_from(f32::MIN_POSITIVE), bf16::MIN_POSITIVE);
1484        // -1.625 << 127 is 1 11111110 1010000 is FF50
1485        assert_eq!(
1486            bf16::lossy_from(127f32.exp2() * -1.625),
1487            bf16::from_bits(0xFF50)
1488        );
1489        // max is rounded up
1490        assert_eq!(bf16::lossy_from(f32::MAX), bf16::INFINITY);
1491        assert_eq!(
1492            bf16::lossy_from(f32::from_bits(0x4175_7FFF)),
1493            bf16::from_bits(0x4175)
1494        );
1495        assert_eq!(
1496            bf16::lossy_from(f32::from_bits(0x4175_8000)),
1497            bf16::from_bits(0x4176)
1498        );
1499        assert_eq!(
1500            bf16::lossy_from(f32::from_bits(0x4175_8001)),
1501            bf16::from_bits(0x4176)
1502        );
1503        assert_eq!(
1504            bf16::lossy_from(f32::from_bits(0x4176_7FFF)),
1505            bf16::from_bits(0x4176)
1506        );
1507        assert_eq!(
1508            bf16::lossy_from(f32::from_bits(0x4176_8000)),
1509            bf16::from_bits(0x4176)
1510        );
1511        assert_eq!(
1512            bf16::lossy_from(f32::from_bits(0x4176_8001)),
1513            bf16::from_bits(0x4177)
1514        );
1515
1516        assert_eq!(bf16::lossy_from(f64::NEG_INFINITY), bf16::NEG_INFINITY);
1517        assert!(bf16::lossy_from(f64::NAN).is_nan());
1518        assert_eq!(bf16::lossy_from(1e-100f64), bf16::from_bits(0));
1519        // -1.625 << 127 is 1 11111110 1010000 is FF50
1520        assert_eq!(
1521            bf16::lossy_from(127f64.exp2() * -1.625),
1522            bf16::from_bits(0xFF50)
1523        );
1524        assert_eq!(bf16::lossy_from(128f64.exp2()), bf16::INFINITY);
1525        // 1.0 >> 133 is minimum non-zero subnormal 0 0000000 0000001
1526        assert_eq!(bf16::lossy_from((-133f64).exp2()), bf16::from_bits(0x0001));
1527        assert_eq!(
1528            bf16::lossy_from((-133f64).exp2() * 0.5001),
1529            bf16::from_bits(0x0001)
1530        );
1531        assert_eq!(bf16::lossy_from((-133f32).exp2() * 0.5), bf16::from_bits(0));
1532    }
1533}