1use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
4
5macro_rules! fixed_impl {
7 ($name:ident, $bits:literal, $fract_bits:literal, $ty:ty) => {
8 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
9 #[cfg_attr(feature = "bytemuck", derive(bytemuck::AnyBitPattern, bytemuck::NoUninit))]
10 #[repr(transparent)]
11 #[doc = concat!(stringify!($bits), "-bit signed fixed point number with ", stringify!($fract_bits), " bits of fraction." )]
12 pub struct $name($ty);
13 impl $name {
14 pub const MIN: Self = Self(<$ty>::MIN);
16
17 pub const MAX: Self = Self(<$ty>::MAX);
19
20 pub const EPSILON: Self = Self(1);
22
23 pub const ZERO: Self = Self(0);
25
26 pub const ONE: Self = Self(1 << $fract_bits);
28
29 pub const NEG_ONE: Self = Self((!0 << $fract_bits) as $ty);
31
32 const INT_MASK: $ty = !0 << $fract_bits;
33 const ROUND: $ty = 1 << ($fract_bits - 1);
34 const FRACT_BITS: usize = $fract_bits;
35
36 #[inline(always)]
38 pub const fn from_bits(bits: $ty) -> Self {
39 Self(bits)
40 }
41
42 #[inline(always)]
44 pub const fn to_bits(self) -> $ty {
45 self.0
46 }
47
48 #[inline(always)]
51 pub const fn round(self) -> Self {
52 Self(self.0.wrapping_add(Self::ROUND) & Self::INT_MASK)
53 }
54
55 #[inline(always)]
57 pub const fn abs(self) -> Self {
58 Self(self.0.wrapping_abs())
59 }
60
61 #[inline(always)]
63 pub const fn floor(self) -> Self {
64 Self(self.0 & Self::INT_MASK)
65 }
66
67 #[inline(always)]
69 pub const fn fract(self) -> Self {
70 Self(self.0 - self.floor().0)
71 }
72
73 #[inline(always)]
75 pub fn wrapping_add(self, other: Self) -> Self {
76 Self(self.0.wrapping_add(other.0))
77 }
78
79 #[inline(always)]
81 pub const fn saturating_add(self, other: Self) -> Self {
82 Self(self.0.saturating_add(other.0))
83 }
84
85 #[inline(always)]
87 pub fn checked_add(self, other: Self) -> Option<Self> {
88 self.0.checked_add(other.0).map(|inner| Self(inner))
89 }
90
91 #[inline(always)]
93 pub const fn wrapping_sub(self, other: Self) -> Self {
94 Self(self.0.wrapping_sub(other.0))
95 }
96
97 #[inline(always)]
99 pub const fn saturating_sub(self, other: Self) -> Self {
100 Self(self.0.saturating_sub(other.0))
101 }
102
103 #[inline(always)]
105 pub const fn to_be_bytes(self) -> [u8; $bits / 8] {
106 self.0.to_be_bytes()
107 }
108 }
109
110 impl Add for $name {
111 type Output = Self;
112 #[inline(always)]
113 fn add(self, other: Self) -> Self {
114 Self(self.0.wrapping_add(other.0))
115 }
116 }
117
118 impl AddAssign for $name {
119 #[inline(always)]
120 fn add_assign(&mut self, other: Self) {
121 *self = *self + other;
122 }
123 }
124
125 impl Sub for $name {
126 type Output = Self;
127 #[inline(always)]
128 fn sub(self, other: Self) -> Self {
129 Self(self.0.wrapping_sub(other.0))
130 }
131 }
132
133 impl SubAssign for $name {
134 #[inline(always)]
135 fn sub_assign(&mut self, other: Self) {
136 *self = *self - other;
137 }
138 }
139
140 impl Neg for $name {
141 type Output = Self;
142 #[inline(always)]
143 fn neg(self) -> Self {
144 Self(self.0.wrapping_neg())
145 }
146 }
147 };
148}
149
150impl Fixed {
151 #[inline]
155 pub const fn mul_div(&self, a: Self, b: Self) -> Self {
156 let mut sign = 1;
157 let mut su = self.0 as u64;
158 let mut au = a.0 as u64;
159 let mut bu = b.0 as u64;
160 if self.0 < 0 {
161 su = 0u64.wrapping_sub(su);
162 sign = -1;
163 }
164 if a.0 < 0 {
165 au = 0u64.wrapping_sub(au);
166 sign = -sign;
167 }
168 if b.0 < 0 {
169 bu = 0u64.wrapping_sub(bu);
170 sign = -sign;
171 }
172 let result = if bu > 0 {
173 su.wrapping_mul(au).wrapping_add(bu >> 1) / bu
174 } else {
175 0x7FFFFFFF
176 };
177 Self(if sign < 0 {
178 (result as i32).wrapping_neg()
179 } else {
180 result as i32
181 })
182 }
183}
184
185impl Mul for Fixed {
186 type Output = Self;
187
188 #[inline(always)]
189 fn mul(self, other: Self) -> Self::Output {
190 let ab = self.0 as i64 * other.0 as i64;
191 Self(((ab + 0x8000 - i64::from(ab < 0)) >> 16) as i32)
192 }
193}
194
195impl Div for Fixed {
196 type Output = Self;
197
198 fn div(self, other: Self) -> Self {
199 let sign = (self.0 < 0) ^ (other.0 < 0);
200 let au = self.0.unsigned_abs() as u64;
201 let bu = other.0.unsigned_abs() as u64;
202 let q = if bu == 0 {
203 0x7FFFFFFF_u32
204 } else {
205 (((au << 16) + (bu >> 1)) / bu) as u32
206 };
207 Self(if sign {
208 (q as i32).wrapping_neg()
209 } else {
210 q as i32
211 })
212 }
213}
214
215impl Mul for F26Dot6 {
216 type Output = Self;
217
218 #[inline(always)]
219 fn mul(self, other: Self) -> Self::Output {
220 let ab = self.0 as i64 * other.0 as i64;
221 Self(((ab + 32 - i64::from(ab < 0)) >> 6) as i32)
222 }
223}
224
225impl Div for F26Dot6 {
226 type Output = Self;
227
228 fn div(self, other: Self) -> Self {
229 let sign = (self.0 < 0) ^ (other.0 < 0);
230 let au = self.0.unsigned_abs() as u64;
231 let bu = other.0.unsigned_abs() as u64;
232 let q = if bu == 0 {
233 0x7FFFFFFF_u32
234 } else {
235 (((au << 6) + (bu >> 1)) / bu) as u32
236 };
237 Self(if sign {
238 (q as i32).wrapping_neg()
239 } else {
240 q as i32
241 })
242 }
243}
244
245macro_rules! fixed_mul_div_assign {
248 ($ty:ty) => {
249 impl MulAssign for $ty {
250 #[inline(always)]
251 fn mul_assign(&mut self, rhs: Self) {
252 *self = *self * rhs;
253 }
254 }
255
256 impl DivAssign for $ty {
257 #[inline(always)]
258 fn div_assign(&mut self, rhs: Self) {
259 *self = *self / rhs;
260 }
261 }
262 };
263}
264
265macro_rules! float_conv {
270 ($name:ident, $to:ident, $from:ident, $ty:ty) => {
272 float_conv!($name, $to, $from, $ty, no_fmt);
273
274 impl std::fmt::Display for $name {
276 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
277 self.$to().fmt(f)
278 }
279 }
280
281 impl std::fmt::Debug for $name {
282 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
283 self.$to().fmt(f)
284 }
285 }
286
287 #[cfg(feature = "serde")]
288 impl ::serde::Serialize for $name {
289 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
290 where
291 S: ::serde::Serializer,
292 {
293 <$ty>::serialize(&$name::$to(*self), serializer)
294 }
295 }
296
297 #[cfg(feature = "serde")]
298 impl<'de> ::serde::Deserialize<'de> for $name {
299 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
300 where
301 D: ::serde::Deserializer<'de>,
302 {
303 <$ty>::deserialize(deserializer).map($name::$from)
304 }
305 }
306 };
307 ($name:ident, $to:ident, $from:ident, $ty:ty, no_fmt) => {
310 impl $name {
311 #[doc = concat!("Creates a fixed point value from a ", stringify!($ty), ".")]
312 #[inline(always)]
316 pub fn $from(x: $ty) -> Self {
317 let frac = (x.is_sign_positive() as u8 as $ty) - 0.5;
320 Self((x * Self::ONE.0 as $ty + frac) as _)
321 }
322
323 #[doc = concat!("Returns the value as an ", stringify!($ty), ".")]
324 #[inline(always)]
328 pub fn $to(self) -> $ty {
329 let int = ((self.0 & Self::INT_MASK) >> Self::FRACT_BITS) as $ty;
330 let fract = (self.0 & !Self::INT_MASK) as $ty / Self::ONE.0 as $ty;
331 int + fract
332 }
333 }
334 };
335}
336
337fixed_impl!(F2Dot14, 16, 14, i16);
338fixed_impl!(F4Dot12, 16, 12, i16);
339fixed_impl!(F6Dot10, 16, 10, i16);
340fixed_impl!(Fixed, 32, 16, i32);
341fixed_impl!(F26Dot6, 32, 6, i32);
342fixed_impl!(F48Dot16, 64, 16, i64);
343
344fixed_mul_div_assign!(Fixed);
345fixed_mul_div_assign!(F26Dot6);
346
347float_conv!(F2Dot14, to_f32, from_f32, f32);
348float_conv!(F4Dot12, to_f32, from_f32, f32);
349float_conv!(F6Dot10, to_f32, from_f32, f32);
350float_conv!(F48Dot16, to_f64, from_f64, f64);
351float_conv!(F2Dot14, to_f64, from_f64, f64, no_fmt);
352float_conv!(F4Dot12, to_f64, from_f64, f64, no_fmt);
353float_conv!(F6Dot10, to_f64, from_f64, f64, no_fmt);
354
355float_conv!(Fixed, to_f64, from_f64, f64);
356float_conv!(F26Dot6, to_f64, from_f64, f64);
357crate::newtype_scalar!(F2Dot14, [u8; 2]);
358crate::newtype_scalar!(F4Dot12, [u8; 2]);
359crate::newtype_scalar!(F6Dot10, [u8; 2]);
360crate::newtype_scalar!(Fixed, [u8; 4]);
361
362impl Fixed {
363 #[inline(always)]
365 pub const fn from_i32(i: i32) -> Self {
366 Self(i << 16)
367 }
368
369 #[inline(always)]
372 pub const fn to_i32(self) -> i32 {
373 self.0.wrapping_add(0x8000) >> 16
374 }
375
376 #[inline(always)]
378 pub const fn to_f26dot6(self) -> F26Dot6 {
379 F26Dot6(self.0.wrapping_add(0x200) >> 10)
380 }
381
382 #[inline(always)]
390 pub const fn to_f2dot14(self) -> F2Dot14 {
391 F2Dot14((self.0.wrapping_add(2) >> 2) as _)
392 }
393
394 #[inline(always)]
399 pub fn to_f32(self) -> f32 {
400 const SCALE_FACTOR: f32 = 1.0 / 65536.0;
401 self.0 as f32 * SCALE_FACTOR
402 }
403
404 #[inline(always)]
408 pub const fn to_f48dot16(self) -> F48Dot16 {
409 F48Dot16(self.0 as i64)
410 }
411
412 #[inline(always)]
420 pub fn apply_delta(self, delta: F48Dot16) -> f32 {
421 self.to_f32() + (delta.to_f64() / 65536.0) as f32
422 }
423
424 #[inline(always)]
433 pub const fn mul_i32(self, value: i32) -> F48Dot16 {
434 F48Dot16((self.0 as i64).wrapping_mul(value as i64))
435 }
436}
437
438impl From<i32> for Fixed {
439 fn from(value: i32) -> Self {
440 Self::from_i32(value)
441 }
442}
443
444impl F26Dot6 {
445 #[inline(always)]
447 pub const fn from_i32(i: i32) -> Self {
448 Self(i << 6)
449 }
450
451 #[inline(always)]
454 pub const fn to_i32(self) -> i32 {
455 self.0.wrapping_add(32) >> 6
456 }
457
458 #[inline(always)]
463 pub fn to_f32(self) -> f32 {
464 const SCALE_FACTOR: f32 = 1.0 / 64.0;
465 self.0 as f32 * SCALE_FACTOR
466 }
467}
468
469impl F48Dot16 {
470 #[inline(always)]
472 pub const fn from_i64(i: i64) -> Self {
473 Self(i << 16)
474 }
475
476 #[inline(always)]
478 pub const fn from_i32(i: i32) -> Self {
479 Self((i as i64) << 16)
480 }
481
482 #[inline(always)]
485 pub const fn to_i64(self) -> i64 {
486 self.0.wrapping_add(0x8000) >> 16
487 }
488
489 #[inline(always)]
494 pub const fn to_i32(self) -> i32 {
495 self.to_i64() as i32
496 }
497
498 #[inline(always)]
503 pub const fn to_f32(self) -> f32 {
504 const SCALE_FACTOR: f64 = 1.0 / 65536.0;
505 (self.0 as f64 * SCALE_FACTOR) as f32
506 }
507
508 #[inline(always)]
513 pub const fn to_fixed(self) -> Fixed {
514 Fixed(self.0 as i32)
515 }
516}
517
518impl F2Dot14 {
519 #[inline(always)]
527 pub fn apply_delta(self, delta: F48Dot16) -> f32 {
528 self.to_f32() + (delta.to_f64() / 16384.0) as f32
529 }
530
531 #[inline(always)]
533 pub const fn to_fixed(self) -> Fixed {
534 Fixed(self.0 as i32 * 4)
535 }
536}
537
538#[cfg(test)]
539mod tests {
540 #![allow(overflowing_literals)] use super::*;
542
543 #[test]
544 fn f2dot14_floats() {
545 assert_eq!(F2Dot14(0x7fff), F2Dot14::from_f32(1.999939));
547 assert_eq!(F2Dot14(0x7000), F2Dot14::from_f32(1.75));
548 assert_eq!(F2Dot14(0x0001), F2Dot14::from_f32(0.0000610356));
549 assert_eq!(F2Dot14(0x0000), F2Dot14::from_f32(0.0));
550 assert_eq!(F2Dot14(0xffff), F2Dot14::from_f32(-0.000061));
551 assert_eq!(F2Dot14(0x8000), F2Dot14::from_f32(-2.0));
552 }
553
554 #[test]
555 fn roundtrip_f2dot14() {
556 for i in i16::MIN..=i16::MAX {
557 let val = F2Dot14(i);
558 assert_eq!(val, F2Dot14::from_f32(val.to_f32()));
559 }
560 }
561
562 #[test]
563 fn round_f2dot14() {
564 assert_eq!(F2Dot14(0x7000).round(), F2Dot14::from_f32(-2.0));
565 assert_eq!(F2Dot14(0x1F00).round(), F2Dot14::from_f32(0.0));
566 assert_eq!(F2Dot14(0x2000).round(), F2Dot14::from_f32(1.0));
567 }
568
569 #[test]
570 fn round_fixed() {
571 assert_eq!(Fixed(0x0001_7FFE).round(), Fixed(0x0001_0000));
573 assert_eq!(Fixed(0x0001_7FFF).round(), Fixed(0x0001_0000));
574 assert_eq!(Fixed(0x0001_8000).round(), Fixed(0x0002_0000));
575 }
576
577 #[test]
587 fn fixed_floats() {
588 assert_eq!(Fixed(0x7fff_0000), Fixed::from_f64(32767.));
589 assert_eq!(Fixed(0x7000_0001), Fixed::from_f64(28672.00001525879));
590 assert_eq!(Fixed(0x0001_0000), Fixed::from_f64(1.0));
591 assert_eq!(Fixed(0x0000_0000), Fixed::from_f64(0.0));
592 assert_eq!(
593 Fixed(i32::from_be_bytes([0xff; 4])),
594 Fixed::from_f64(-0.000015259)
595 );
596 assert_eq!(Fixed(0x7fff_ffff), Fixed::from_f64(32768.0));
597 }
598
599 #[test]
603 fn fixed_floats_rounding() {
604 fn with_round_intrinsic(x: f64) -> Fixed {
605 Fixed((x * 65536.0).round() as i32)
606 }
607 let inputs = [0.05, 0.6, 0.2, 0.4, 0.67755];
609 for input in inputs {
610 assert_eq!(Fixed::from_f64(input), with_round_intrinsic(input));
611 assert_eq!(Fixed::from_f64(-input), with_round_intrinsic(-input));
613 }
614 }
615
616 #[test]
617 fn fixed_to_int() {
618 assert_eq!(Fixed::from_f64(1.0).to_i32(), 1);
619 assert_eq!(Fixed::from_f64(1.5).to_i32(), 2);
620 assert_eq!(F26Dot6::from_f64(1.0).to_i32(), 1);
621 assert_eq!(F26Dot6::from_f64(1.5).to_i32(), 2);
622 }
623
624 #[test]
625 fn fixed_from_int() {
626 assert_eq!(Fixed::from_i32(1000).to_bits(), 1000 << 16);
627 assert_eq!(F26Dot6::from_i32(1000).to_bits(), 1000 << 6);
628 }
629
630 #[test]
631 fn fixed_to_f26dot6() {
632 assert_eq!(Fixed::from_f64(42.5).to_f26dot6(), F26Dot6::from_f64(42.5));
633 }
634
635 #[test]
636 fn fixed_muldiv() {
637 assert_eq!(
638 Fixed::from_f64(0.5) * Fixed::from_f64(2.0),
639 Fixed::from_f64(1.0)
640 );
641 assert_eq!(
642 Fixed::from_f64(0.5) / Fixed::from_f64(2.0),
643 Fixed::from_f64(0.25)
644 );
645 }
646
647 #[test]
651 fn fixed_div_neg_overflow() {
652 let a = Fixed::from_f64(-92.5);
653 let b = Fixed::from_f64(0.0028228759765625);
654 let _ = a / b;
656 }
657
658 #[test]
659 fn fixed_mul_div_neg_overflow() {
660 let a = Fixed::from_f64(-92.5);
661 let b = Fixed::from_f64(0.0028228759765625);
662 let _ = a.mul_div(Fixed::ONE, b);
664 }
665
666 #[test]
667 fn fixed_div_min_value() {
668 let min = Fixed(i32::MIN);
670 let one = Fixed::ONE;
671 let _ = min / one;
673 let neg_one = Fixed(-Fixed::ONE.0);
675 let _ = min / neg_one;
676 }
677
678 #[test]
679 fn fixed_abs_min_value() {
680 assert_eq!(Fixed(i32::MIN).abs(), Fixed(i32::MIN));
683 }
684
685 #[test]
686 fn fixed_neg_min_value() {
687 assert_eq!(-Fixed(i32::MIN), Fixed(i32::MIN));
690 }
691
692 #[test]
693 fn f48dot16_floats() {
694 assert_eq!(F48Dot16(0x0001_0000), F48Dot16::from_f64(1.0));
695 assert_eq!(F48Dot16(0x0000_0000), F48Dot16::from_f64(0.0));
696 assert_eq!(F48Dot16(0x0001_8000), F48Dot16::from_f64(1.5));
697 assert_eq!(F48Dot16(-0x0001_8000), F48Dot16::from_f64(-1.5));
698 assert_eq!(F48Dot16(0x0000_0001), F48Dot16::EPSILON);
699 assert_eq!(
701 F48Dot16((1i64 << 40) * 65536),
702 F48Dot16::from_f64((1u64 << 40) as f64)
703 );
704 assert_eq!(
705 F48Dot16::from_f64(1099511627776.5).to_f64(),
706 1099511627776.5
707 );
708 }
709
710 #[test]
711 fn f48dot16_round() {
712 assert_eq!(F48Dot16(0x0001_7FFF).round(), F48Dot16(0x0001_0000));
713 assert_eq!(F48Dot16(0x0001_8000).round(), F48Dot16(0x0002_0000));
714 assert_eq!(F48Dot16::from_f64(-1.5).round(), F48Dot16::from_f64(-1.0));
715 }
716
717 #[test]
718 fn f48dot16_to_int() {
719 assert_eq!(F48Dot16::from_f64(1.0).to_i64(), 1);
720 assert_eq!(F48Dot16::from_f64(1.5).to_i64(), 2);
721 assert_eq!(F48Dot16::from_f64(-1.5).to_i64(), -1);
722 assert_eq!(F48Dot16::from_f64(1099511627776.25).to_i64(), 1099511627776);
723 }
724
725 #[test]
726 fn f48dot16_from_int() {
727 assert_eq!(F48Dot16::from_i64(1000).to_bits(), 1000 << 16);
728 assert_eq!(F48Dot16::from_i64(1 << 40).to_bits(), 1 << 56);
729 }
730
731 #[test]
734 fn f48dot16_fixed_conversions() {
735 for bits in [0, 1, -1, 0x1234_5678, i32::MAX, i32::MIN] {
736 let fixed = Fixed(bits);
737 let wide = fixed.to_f48dot16();
738 assert_eq!(wide.to_bits(), bits as i64);
739 assert_eq!(wide.to_fixed(), fixed);
740 }
741 assert_eq!(F48Dot16(i32::MAX as i64 + 1).to_fixed(), Fixed(i32::MIN));
744 assert_eq!(F48Dot16(i32::MIN as i64 - 1).to_fixed(), Fixed(i32::MAX));
745 }
746
747 #[test]
748 fn f48dot16_mul_i32() {
749 assert_eq!(Fixed::from_f64(0.5).mul_i32(3), F48Dot16::from_f64(1.5));
750 assert_eq!(Fixed::ONE.mul_i32(-7), F48Dot16::from_i64(-7));
751 assert_eq!(Fixed::ZERO.mul_i32(i32::MAX), F48Dot16::ZERO);
752 assert_eq!(Fixed(i32::MIN).mul_i32(i32::MIN), F48Dot16(1i64 << 62));
755 }
756
757 #[test]
760 fn f48dot16_delta_accumulation() {
761 let deltas = [100i32, -250, 37];
762 let scalars = [
763 Fixed::from_f64(1.0),
764 Fixed::from_f64(0.5),
765 Fixed::from_f64(0.25),
766 ];
767 let mut accum = F48Dot16::ZERO;
768 for (delta, scalar) in deltas.iter().zip(&scalars) {
769 accum += scalar.mul_i32(*delta);
770 }
771 assert_eq!(accum, F48Dot16::from_f64(-15.75));
773 assert_eq!(accum.to_i64(), -16);
774 assert_eq!(accum.round(), F48Dot16::from_f64(-16.0));
775 }
776
777 #[test]
781 fn f48dot16_apply_delta() {
782 let raws = [0i64, 1, -1, 100, -32768, 65536, 1 << 40, -(1 << 40)];
783 for raw_bits in raws {
784 let delta = F48Dot16(raw_bits);
785 let raw = delta.to_f64();
786 let base = Fixed::from_f64(1.5);
788 assert_eq!(
789 base.apply_delta(delta),
790 base.to_f32() + (raw * (1.0 / 65536.0)) as f32
791 );
792 let base = F2Dot14::from_f32(0.25);
794 assert_eq!(
795 base.apply_delta(delta),
796 base.to_f32() + (raw * (1.0 / 16384.0)) as f32
797 );
798 }
799 assert_eq!(
801 Fixed::ZERO.apply_delta(F48Dot16::from_i64(1)),
802 1.0 / 65536.0
803 );
804 assert_eq!(
805 F2Dot14::from_f32(0.0).apply_delta(F48Dot16::from_i64(1)),
806 1.0 / 16384.0
807 );
808 assert_eq!(
809 F2Dot14::from_f32(0.5).apply_delta(F48Dot16::from_f64(-0.5)),
810 0.5 - 0.5 / 16384.0
811 );
812 }
813
814 #[test]
815 fn f26dot6_muldiv() {
816 assert_eq!(
817 F26Dot6::from_f64(0.5) * F26Dot6::from_f64(2.0),
818 F26Dot6::from_f64(1.0)
819 );
820 assert_eq!(
821 F26Dot6::from_f64(0.5) * F26Dot6::from_f64(-2.4),
822 F26Dot6::from_f64(-1.2)
823 );
824 assert_eq!(F26Dot6::ONE * F26Dot6::ONE, F26Dot6::ONE);
825 assert_eq!(
826 F26Dot6::from_f64(0.5) / F26Dot6::from_f64(2.0),
827 F26Dot6::from_f64(0.25)
828 );
829 assert_eq!(
830 F26Dot6::from_f64(0.5) / F26Dot6::from_f64(-2.4),
831 F26Dot6::from_f64(-0.20833333333333334)
832 );
833 assert_eq!(
834 F26Dot6::from_f64(2.0) / F26Dot6::from_f64(3.0),
835 F26Dot6::from_f64(0.6666666666666666)
836 );
837 assert_eq!(F26Dot6::ONE / F26Dot6::ONE, F26Dot6::ONE);
838 assert_eq!(F26Dot6::ONE / F26Dot6::ZERO, F26Dot6(0x7FFFFFFF));
839 assert_eq!(-F26Dot6::ONE / F26Dot6::ZERO, F26Dot6(-0x7FFFFFFF));
840 }
841
842 #[cfg(feature = "serde")]
843 mod serde {
844 use super::*;
845
846 macro_rules! roundtrip_one {
847 ($fixed:ident) => {{
848 let before = <$fixed>::ONE;
849 let serialized = ::serde_json::to_string(&before).expect("should serialize");
850 assert_eq!(&serialized, "1.0");
851 let after = ::serde_json::from_str(&serialized).expect("should deserialize");
852 assert_eq!(before, after);
853 }};
854 }
855
856 #[test]
857 fn one_is_one_f2dot14() {
858 roundtrip_one!(F2Dot14);
859 }
860
861 #[test]
862 fn one_is_one_f4dot12() {
863 roundtrip_one!(F4Dot12);
864 }
865
866 #[test]
867 fn one_is_one_f6dot10() {
868 roundtrip_one!(F6Dot10);
869 }
870
871 #[test]
872 fn one_is_one_fixed() {
873 roundtrip_one!(Fixed);
874 }
875
876 #[test]
877 fn one_is_one_f26dot6() {
878 roundtrip_one!(F26Dot6);
879 }
880
881 macro_rules! roundtrip_all {
882 ($fixed:ident, $ty:ty) => {
883 for raw in <$ty>::MIN..=<$ty>::MAX {
884 let fixed = $fixed(raw);
885 let fixed_float = fixed.to_f64();
886
887 let json_value = ::serde_json::to_value(&fixed).expect("should serialize");
888 let json_float = json_value
889 .as_f64()
890 .expect("serde didn't serialize the value to a float");
891
892 assert_eq!(
896 fixed_float,
897 json_float,
898 "failed on {raw} ({fixed_type}({raw:#X})): {json_float} != {fixed_float}",
899 fixed_type = ::std::stringify!($fixed),
900 );
901 }
902 };
903 }
904
905 #[test]
906 fn roundtrip_all_f2dot14() {
907 roundtrip_all!(F2Dot14, i16);
908 }
909
910 #[test]
911 fn roundtrip_all_f4dot12() {
912 roundtrip_all!(F4Dot12, i16);
913 }
914
915 #[test]
916 fn roundtrip_all_f6dot10() {
917 roundtrip_all!(F6Dot10, i16);
918 }
919
920 #[test]
921 #[ignore = "enumerating all i32 values takes a while"]
922 fn roundtrip_all_fixed() {
923 roundtrip_all!(Fixed, i32);
924 }
925
926 #[test]
927 #[ignore = "enumerating all i32 values takes a while"]
928 fn roundtrip_all_f26dot6() {
929 roundtrip_all!(F26Dot6, i32);
930 }
931 }
932}