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 {
275 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
276 if f.precision().is_some() {
277 return std::fmt::Display::fmt(&self.$to(), f);
278 }
279 fmt_shortest(self.0 as i64, Self::FRACT_BITS as u32, f)
280 }
281 }
282
283 impl std::fmt::Debug for $name {
284 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
285 std::fmt::Display::fmt(self, f)
286 }
287 }
288
289 #[cfg(feature = "serde")]
290 impl ::serde::Serialize for $name {
291 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
292 where
293 S: ::serde::Serializer,
294 {
295 <$ty>::serialize(&$name::$to(*self), serializer)
296 }
297 }
298
299 #[cfg(feature = "serde")]
300 impl<'de> ::serde::Deserialize<'de> for $name {
301 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
302 where
303 D: ::serde::Deserializer<'de>,
304 {
305 <$ty>::deserialize(deserializer).map($name::$from)
306 }
307 }
308 };
309 ($name:ident, $to:ident, $from:ident, $ty:ty, no_fmt) => {
312 impl $name {
313 #[doc = concat!("Creates a fixed point value from a ", stringify!($ty), ".")]
314 #[inline(always)]
318 pub fn $from(x: $ty) -> Self {
319 let frac = (x.is_sign_positive() as u8 as $ty) - 0.5;
322 Self((x * Self::ONE.0 as $ty + frac) as _)
323 }
324
325 #[doc = concat!("Returns the value as an ", stringify!($ty), ".")]
326 #[inline(always)]
330 pub fn $to(self) -> $ty {
331 let int = ((self.0 & Self::INT_MASK) >> Self::FRACT_BITS) as $ty;
332 let fract = (self.0 & !Self::INT_MASK) as $ty / Self::ONE.0 as $ty;
333 int + fract
334 }
335 }
336 };
337}
338
339fn fmt_shortest(raw: i64, fract_bits: u32, f: &mut std::fmt::Formatter) -> std::fmt::Result {
347 let one = 1u128 << fract_bits;
348 let magnitude = u128::from(raw.unsigned_abs());
349 for places in 0..=5 {
350 let pow = 10u128.pow(places);
351 let digits = (2 * magnitude * pow + one) / (2 * one);
352 if (digits * one).abs_diff(magnitude * pow) * 2 < pow {
353 let mut buf = [0u8; 32];
354 return f.pad_integral(raw >= 0, "", write_decimal(digits, places, &mut buf));
355 }
356 }
357 unreachable!()
360}
361
362fn write_decimal(mut digits: u128, places: u32, buf: &mut [u8; 32]) -> &str {
364 let mut pos = buf.len();
365 let mut written = 0;
366 while written <= places || digits != 0 {
367 if written == places && places != 0 {
368 pos -= 1;
369 buf[pos] = b'.';
370 }
371 pos -= 1;
372 buf[pos] = b'0' + (digits % 10) as u8;
373 digits /= 10;
374 written += 1;
375 }
376 std::str::from_utf8(&buf[pos..]).expect("only ASCII digits and '.'")
377}
378
379fixed_impl!(F2Dot14, 16, 14, i16);
380fixed_impl!(F4Dot12, 16, 12, i16);
381fixed_impl!(F6Dot10, 16, 10, i16);
382fixed_impl!(Fixed, 32, 16, i32);
383fixed_impl!(F26Dot6, 32, 6, i32);
384fixed_impl!(F48Dot16, 64, 16, i64);
385
386fixed_mul_div_assign!(Fixed);
387fixed_mul_div_assign!(F26Dot6);
388
389float_conv!(F2Dot14, to_f32, from_f32, f32);
390float_conv!(F4Dot12, to_f32, from_f32, f32);
391float_conv!(F6Dot10, to_f32, from_f32, f32);
392float_conv!(F48Dot16, to_f64, from_f64, f64);
393float_conv!(F2Dot14, to_f64, from_f64, f64, no_fmt);
394float_conv!(F4Dot12, to_f64, from_f64, f64, no_fmt);
395float_conv!(F6Dot10, to_f64, from_f64, f64, no_fmt);
396
397float_conv!(Fixed, to_f64, from_f64, f64);
398float_conv!(F26Dot6, to_f64, from_f64, f64);
399crate::newtype_scalar!(F2Dot14, [u8; 2]);
400crate::newtype_scalar!(F4Dot12, [u8; 2]);
401crate::newtype_scalar!(F6Dot10, [u8; 2]);
402crate::newtype_scalar!(Fixed, [u8; 4]);
403
404impl Fixed {
405 #[inline(always)]
407 pub const fn from_i32(i: i32) -> Self {
408 Self(i << 16)
409 }
410
411 #[inline(always)]
414 pub const fn to_i32(self) -> i32 {
415 self.0.wrapping_add(0x8000) >> 16
416 }
417
418 #[inline(always)]
420 pub const fn to_f26dot6(self) -> F26Dot6 {
421 F26Dot6(self.0.wrapping_add(0x200) >> 10)
422 }
423
424 #[inline(always)]
432 pub const fn to_f2dot14(self) -> F2Dot14 {
433 F2Dot14((self.0.wrapping_add(2) >> 2) as _)
434 }
435
436 #[inline(always)]
441 pub fn to_f32(self) -> f32 {
442 const SCALE_FACTOR: f32 = 1.0 / 65536.0;
443 self.0 as f32 * SCALE_FACTOR
444 }
445
446 #[inline(always)]
450 pub const fn to_f48dot16(self) -> F48Dot16 {
451 F48Dot16(self.0 as i64)
452 }
453
454 #[inline(always)]
462 pub fn apply_delta(self, delta: F48Dot16) -> f32 {
463 self.to_f32() + (delta.to_f64() / 65536.0) as f32
464 }
465
466 #[inline(always)]
475 pub const fn mul_i32(self, value: i32) -> F48Dot16 {
476 F48Dot16((self.0 as i64).wrapping_mul(value as i64))
477 }
478}
479
480impl From<i32> for Fixed {
481 fn from(value: i32) -> Self {
482 Self::from_i32(value)
483 }
484}
485
486impl F26Dot6 {
487 #[inline(always)]
489 pub const fn from_i32(i: i32) -> Self {
490 Self(i << 6)
491 }
492
493 #[inline(always)]
496 pub const fn to_i32(self) -> i32 {
497 self.0.wrapping_add(32) >> 6
498 }
499
500 #[inline(always)]
505 pub fn to_f32(self) -> f32 {
506 const SCALE_FACTOR: f32 = 1.0 / 64.0;
507 self.0 as f32 * SCALE_FACTOR
508 }
509}
510
511impl F48Dot16 {
512 #[inline(always)]
514 pub const fn from_i64(i: i64) -> Self {
515 Self(i << 16)
516 }
517
518 #[inline(always)]
520 pub const fn from_i32(i: i32) -> Self {
521 Self((i as i64) << 16)
522 }
523
524 #[inline(always)]
527 pub const fn to_i64(self) -> i64 {
528 self.0.wrapping_add(0x8000) >> 16
529 }
530
531 #[inline(always)]
536 pub const fn to_i32(self) -> i32 {
537 self.to_i64() as i32
538 }
539
540 #[inline(always)]
545 pub const fn to_f32(self) -> f32 {
546 const SCALE_FACTOR: f64 = 1.0 / 65536.0;
547 (self.0 as f64 * SCALE_FACTOR) as f32
548 }
549
550 #[inline(always)]
555 pub const fn to_fixed(self) -> Fixed {
556 Fixed(self.0 as i32)
557 }
558}
559
560impl F2Dot14 {
561 #[inline(always)]
569 pub fn apply_delta(self, delta: F48Dot16) -> f32 {
570 self.to_f32() + (delta.to_f64() / 16384.0) as f32
571 }
572
573 #[inline(always)]
575 pub const fn to_fixed(self) -> Fixed {
576 Fixed(self.0 as i32 * 4)
577 }
578}
579
580#[cfg(test)]
581mod tests {
582 #![allow(overflowing_literals)] use super::*;
584
585 #[test]
586 fn f2dot14_floats() {
587 assert_eq!(F2Dot14(0x7fff), F2Dot14::from_f32(1.999939));
589 assert_eq!(F2Dot14(0x7000), F2Dot14::from_f32(1.75));
590 assert_eq!(F2Dot14(0x0001), F2Dot14::from_f32(0.0000610356));
591 assert_eq!(F2Dot14(0x0000), F2Dot14::from_f32(0.0));
592 assert_eq!(F2Dot14(0xffff), F2Dot14::from_f32(-0.000061));
593 assert_eq!(F2Dot14(0x8000), F2Dot14::from_f32(-2.0));
594 }
595
596 #[test]
597 fn roundtrip_f2dot14() {
598 for i in i16::MIN..=i16::MAX {
599 let val = F2Dot14(i);
600 assert_eq!(val, F2Dot14::from_f32(val.to_f32()));
601 }
602 }
603
604 #[test]
605 fn round_f2dot14() {
606 assert_eq!(F2Dot14(0x7000).round(), F2Dot14::from_f32(-2.0));
607 assert_eq!(F2Dot14(0x1F00).round(), F2Dot14::from_f32(0.0));
608 assert_eq!(F2Dot14(0x2000).round(), F2Dot14::from_f32(1.0));
609 }
610
611 #[test]
612 fn round_fixed() {
613 assert_eq!(Fixed(0x0001_7FFE).round(), Fixed(0x0001_0000));
615 assert_eq!(Fixed(0x0001_7FFF).round(), Fixed(0x0001_0000));
616 assert_eq!(Fixed(0x0001_8000).round(), Fixed(0x0002_0000));
617 }
618
619 #[test]
629 fn fixed_floats() {
630 assert_eq!(Fixed(0x7fff_0000), Fixed::from_f64(32767.));
631 assert_eq!(Fixed(0x7000_0001), Fixed::from_f64(28672.00001525879));
632 assert_eq!(Fixed(0x0001_0000), Fixed::from_f64(1.0));
633 assert_eq!(Fixed(0x0000_0000), Fixed::from_f64(0.0));
634 assert_eq!(
635 Fixed(i32::from_be_bytes([0xff; 4])),
636 Fixed::from_f64(-0.000015259)
637 );
638 assert_eq!(Fixed(0x7fff_ffff), Fixed::from_f64(32768.0));
639 }
640
641 #[test]
645 fn fixed_floats_rounding() {
646 fn with_round_intrinsic(x: f64) -> Fixed {
647 Fixed((x * 65536.0).round() as i32)
648 }
649 let inputs = [0.05, 0.6, 0.2, 0.4, 0.67755];
651 for input in inputs {
652 assert_eq!(Fixed::from_f64(input), with_round_intrinsic(input));
653 assert_eq!(Fixed::from_f64(-input), with_round_intrinsic(-input));
655 }
656 }
657
658 #[test]
659 fn fixed_to_int() {
660 assert_eq!(Fixed::from_f64(1.0).to_i32(), 1);
661 assert_eq!(Fixed::from_f64(1.5).to_i32(), 2);
662 assert_eq!(F26Dot6::from_f64(1.0).to_i32(), 1);
663 assert_eq!(F26Dot6::from_f64(1.5).to_i32(), 2);
664 }
665
666 #[test]
667 fn fixed_from_int() {
668 assert_eq!(Fixed::from_i32(1000).to_bits(), 1000 << 16);
669 assert_eq!(F26Dot6::from_i32(1000).to_bits(), 1000 << 6);
670 }
671
672 #[test]
673 fn fixed_to_f26dot6() {
674 assert_eq!(Fixed::from_f64(42.5).to_f26dot6(), F26Dot6::from_f64(42.5));
675 }
676
677 #[test]
678 fn fixed_muldiv() {
679 assert_eq!(
680 Fixed::from_f64(0.5) * Fixed::from_f64(2.0),
681 Fixed::from_f64(1.0)
682 );
683 assert_eq!(
684 Fixed::from_f64(0.5) / Fixed::from_f64(2.0),
685 Fixed::from_f64(0.25)
686 );
687 }
688
689 #[test]
693 fn fixed_div_neg_overflow() {
694 let a = Fixed::from_f64(-92.5);
695 let b = Fixed::from_f64(0.0028228759765625);
696 let _ = a / b;
698 }
699
700 #[test]
701 fn fixed_mul_div_neg_overflow() {
702 let a = Fixed::from_f64(-92.5);
703 let b = Fixed::from_f64(0.0028228759765625);
704 let _ = a.mul_div(Fixed::ONE, b);
706 }
707
708 #[test]
709 fn fixed_div_min_value() {
710 let min = Fixed(i32::MIN);
712 let one = Fixed::ONE;
713 let _ = min / one;
715 let neg_one = Fixed(-Fixed::ONE.0);
717 let _ = min / neg_one;
718 }
719
720 #[test]
721 fn fixed_abs_min_value() {
722 assert_eq!(Fixed(i32::MIN).abs(), Fixed(i32::MIN));
725 }
726
727 #[test]
728 fn fixed_neg_min_value() {
729 assert_eq!(-Fixed(i32::MIN), Fixed(i32::MIN));
732 }
733
734 #[test]
735 fn f48dot16_floats() {
736 assert_eq!(F48Dot16(0x0001_0000), F48Dot16::from_f64(1.0));
737 assert_eq!(F48Dot16(0x0000_0000), F48Dot16::from_f64(0.0));
738 assert_eq!(F48Dot16(0x0001_8000), F48Dot16::from_f64(1.5));
739 assert_eq!(F48Dot16(-0x0001_8000), F48Dot16::from_f64(-1.5));
740 assert_eq!(F48Dot16(0x0000_0001), F48Dot16::EPSILON);
741 assert_eq!(
743 F48Dot16((1i64 << 40) * 65536),
744 F48Dot16::from_f64((1u64 << 40) as f64)
745 );
746 assert_eq!(
747 F48Dot16::from_f64(1099511627776.5).to_f64(),
748 1099511627776.5
749 );
750 }
751
752 #[test]
753 fn f48dot16_round() {
754 assert_eq!(F48Dot16(0x0001_7FFF).round(), F48Dot16(0x0001_0000));
755 assert_eq!(F48Dot16(0x0001_8000).round(), F48Dot16(0x0002_0000));
756 assert_eq!(F48Dot16::from_f64(-1.5).round(), F48Dot16::from_f64(-1.0));
757 }
758
759 #[test]
760 fn f48dot16_to_int() {
761 assert_eq!(F48Dot16::from_f64(1.0).to_i64(), 1);
762 assert_eq!(F48Dot16::from_f64(1.5).to_i64(), 2);
763 assert_eq!(F48Dot16::from_f64(-1.5).to_i64(), -1);
764 assert_eq!(F48Dot16::from_f64(1099511627776.25).to_i64(), 1099511627776);
765 }
766
767 #[test]
768 fn f48dot16_from_int() {
769 assert_eq!(F48Dot16::from_i64(1000).to_bits(), 1000 << 16);
770 assert_eq!(F48Dot16::from_i64(1 << 40).to_bits(), 1 << 56);
771 }
772
773 #[test]
776 fn f48dot16_fixed_conversions() {
777 for bits in [0, 1, -1, 0x1234_5678, i32::MAX, i32::MIN] {
778 let fixed = Fixed(bits);
779 let wide = fixed.to_f48dot16();
780 assert_eq!(wide.to_bits(), bits as i64);
781 assert_eq!(wide.to_fixed(), fixed);
782 }
783 assert_eq!(F48Dot16(i32::MAX as i64 + 1).to_fixed(), Fixed(i32::MIN));
786 assert_eq!(F48Dot16(i32::MIN as i64 - 1).to_fixed(), Fixed(i32::MAX));
787 }
788
789 #[test]
790 fn f48dot16_mul_i32() {
791 assert_eq!(Fixed::from_f64(0.5).mul_i32(3), F48Dot16::from_f64(1.5));
792 assert_eq!(Fixed::ONE.mul_i32(-7), F48Dot16::from_i64(-7));
793 assert_eq!(Fixed::ZERO.mul_i32(i32::MAX), F48Dot16::ZERO);
794 assert_eq!(Fixed(i32::MIN).mul_i32(i32::MIN), F48Dot16(1i64 << 62));
797 }
798
799 #[test]
802 fn f48dot16_delta_accumulation() {
803 let deltas = [100i32, -250, 37];
804 let scalars = [
805 Fixed::from_f64(1.0),
806 Fixed::from_f64(0.5),
807 Fixed::from_f64(0.25),
808 ];
809 let mut accum = F48Dot16::ZERO;
810 for (delta, scalar) in deltas.iter().zip(&scalars) {
811 accum += scalar.mul_i32(*delta);
812 }
813 assert_eq!(accum, F48Dot16::from_f64(-15.75));
815 assert_eq!(accum.to_i64(), -16);
816 assert_eq!(accum.round(), F48Dot16::from_f64(-16.0));
817 }
818
819 #[test]
823 fn f48dot16_apply_delta() {
824 let raws = [0i64, 1, -1, 100, -32768, 65536, 1 << 40, -(1 << 40)];
825 for raw_bits in raws {
826 let delta = F48Dot16(raw_bits);
827 let raw = delta.to_f64();
828 let base = Fixed::from_f64(1.5);
830 assert_eq!(
831 base.apply_delta(delta),
832 base.to_f32() + (raw * (1.0 / 65536.0)) as f32
833 );
834 let base = F2Dot14::from_f32(0.25);
836 assert_eq!(
837 base.apply_delta(delta),
838 base.to_f32() + (raw * (1.0 / 16384.0)) as f32
839 );
840 }
841 assert_eq!(
843 Fixed::ZERO.apply_delta(F48Dot16::from_i64(1)),
844 1.0 / 65536.0
845 );
846 assert_eq!(
847 F2Dot14::from_f32(0.0).apply_delta(F48Dot16::from_i64(1)),
848 1.0 / 16384.0
849 );
850 assert_eq!(
851 F2Dot14::from_f32(0.5).apply_delta(F48Dot16::from_f64(-0.5)),
852 0.5 - 0.5 / 16384.0
853 );
854 }
855
856 #[test]
857 fn f26dot6_muldiv() {
858 assert_eq!(
859 F26Dot6::from_f64(0.5) * F26Dot6::from_f64(2.0),
860 F26Dot6::from_f64(1.0)
861 );
862 assert_eq!(
863 F26Dot6::from_f64(0.5) * F26Dot6::from_f64(-2.4),
864 F26Dot6::from_f64(-1.2)
865 );
866 assert_eq!(F26Dot6::ONE * F26Dot6::ONE, F26Dot6::ONE);
867 assert_eq!(
868 F26Dot6::from_f64(0.5) / F26Dot6::from_f64(2.0),
869 F26Dot6::from_f64(0.25)
870 );
871 assert_eq!(
872 F26Dot6::from_f64(0.5) / F26Dot6::from_f64(-2.4),
873 F26Dot6::from_f64(-0.20833333333333334)
874 );
875 assert_eq!(
876 F26Dot6::from_f64(2.0) / F26Dot6::from_f64(3.0),
877 F26Dot6::from_f64(0.6666666666666666)
878 );
879 assert_eq!(F26Dot6::ONE / F26Dot6::ONE, F26Dot6::ONE);
880 assert_eq!(F26Dot6::ONE / F26Dot6::ZERO, F26Dot6(0x7FFFFFFF));
881 assert_eq!(-F26Dot6::ONE / F26Dot6::ZERO, F26Dot6(-0x7FFFFFFF));
882 }
883
884 #[cfg(feature = "std")]
885 mod display {
886 use super::*;
887
888 #[test]
889 fn f2dot14() {
890 let cases = [
891 (F2Dot14(9830), "0.6"),
892 (F2Dot14(-10139), "-0.61884"),
893 (F2Dot14::ONE, "1"),
894 (F2Dot14::NEG_ONE, "-1"),
895 (F2Dot14::ZERO, "0"),
896 (F2Dot14::MIN, "-2"),
897 (F2Dot14::MAX, "1.99994"),
898 (F2Dot14::EPSILON, "0.00006"),
899 (F2Dot14(-1), "-0.00006"),
900 (F2Dot14::from_f32(0.5), "0.5"),
901 (F2Dot14::from_f32(-0.25), "-0.25"),
902 ];
903 for (value, expected) in cases {
904 assert_eq!(value.to_string(), expected, "{:?}", value.to_bits());
905 }
906 }
907
908 #[test]
909 fn f4dot12_f6dot10() {
910 assert_eq!(F4Dot12::from_f32(0.6).to_string(), "0.6");
911 assert_eq!(F4Dot12::MIN.to_string(), "-8");
912 assert_eq!(F4Dot12::MAX.to_string(), "7.9998");
913 assert_eq!(F6Dot10::from_f32(-0.6).to_string(), "-0.6");
914 assert_eq!(F6Dot10::MIN.to_string(), "-32");
915 assert_eq!(F6Dot10::MAX.to_string(), "31.999");
916 }
917
918 #[test]
919 fn fixed() {
920 let cases = [
921 (Fixed::from_f64(0.6), "0.6"),
922 (Fixed::from_f64(-0.6), "-0.6"),
923 (Fixed::from_f64(-1.5), "-1.5"),
924 (Fixed::from_i32(1000), "1000"),
925 (Fixed::from_f64(32767.5), "32767.5"),
926 (Fixed::MAX, "32767.99998"),
927 (Fixed::MIN, "-32768"),
928 (Fixed::EPSILON, "0.00002"),
929 (Fixed(-1), "-0.00002"),
930 ];
931 for (value, expected) in cases {
932 assert_eq!(value.to_string(), expected, "{:?}", value.to_bits());
933 }
934 }
935
936 #[test]
937 fn f26dot6() {
938 let cases = [
939 (F26Dot6(1), "0.02"),
940 (F26Dot6(-3), "-0.05"),
941 (F26Dot6(32), "0.5"),
942 (F26Dot6(65), "1.02"),
943 (F26Dot6(-96), "-1.5"),
944 (F26Dot6(100 * 64 + 16), "100.25"),
945 (F26Dot6::from_i32(-7), "-7"),
946 (F26Dot6::MIN, "-33554432"),
947 (F26Dot6::MAX, "33554431.98"),
948 ];
949 for (value, expected) in cases {
950 assert_eq!(value.to_string(), expected, "{:?}", value.to_bits());
951 }
952 }
953
954 #[test]
955 fn f48dot16() {
956 let cases = [
957 (F48Dot16::from_f64(0.6), "0.6"),
958 (F48Dot16::from_i64(1 << 40), "1099511627776"),
959 (F48Dot16::from_f64(-1099511627776.5), "-1099511627776.5"),
960 (F48Dot16::MAX, "140737488355327.99998"),
961 (F48Dot16::MIN, "-140737488355328"),
962 (F48Dot16(i64::MIN + 1), "-140737488355327.99998"),
963 ];
964 for (value, expected) in cases {
965 assert_eq!(value.to_string(), expected, "{:?}", value.to_bits());
966 }
967 }
968
969 fn check_shortest(
976 raw: i64,
977 text: &str,
978 fract_bits: u32,
979 from_f64: impl Fn(f64) -> Option<i64>,
980 ) {
981 assert_ne!(text, "-0");
982 let parsed: f64 = text.parse().unwrap();
983 assert_eq!(from_f64(parsed), Some(raw), "{text} does not round-trip");
984 let places = text
985 .split_once('.')
986 .map_or(0, |(_, fract)| fract.len() as u32);
987 if places == 0 {
988 return;
989 }
990 let pow = 10i128.pow(places - 1);
991 let floor = (i128::from(raw) * pow).div_euclid(1 << fract_bits);
992 for shorter in [floor, floor + 1] {
993 let shorter = shorter as f64 / pow as f64;
994 assert_ne!(from_f64(shorter), Some(raw), "{text} could be {shorter}");
995 }
996 }
997
998 macro_rules! check_all {
999 ($fixed:ident, $raws:expr) => {
1000 let one = $fixed::ONE.to_bits() as f64;
1001 let min = ($fixed::MIN.to_bits() as f64 - 0.5) / one;
1002 let max = ($fixed::MAX.to_bits() as f64 + 0.5) / one;
1003 for raw in $raws {
1004 check_shortest(
1005 raw as i64,
1006 &$fixed(raw).to_string(),
1007 $fixed::FRACT_BITS as u32,
1008 |x| (min < x && x < max).then(|| $fixed::from_f64(x).to_bits() as i64),
1009 );
1010 }
1011 };
1012 }
1013
1014 #[test]
1015 fn shortest_all_f2dot14() {
1016 check_all!(F2Dot14, i16::MIN..=i16::MAX);
1017 }
1018
1019 #[test]
1020 fn shortest_all_f4dot12() {
1021 check_all!(F4Dot12, i16::MIN..=i16::MAX);
1022 }
1023
1024 #[test]
1025 fn shortest_all_f6dot10() {
1026 check_all!(F6Dot10, i16::MIN..=i16::MAX);
1027 }
1028
1029 fn sampled_i32() -> impl Iterator<Item = i32> {
1030 (i32::MIN..=i32::MIN + 2000)
1031 .chain(-200_000..=200_000)
1032 .chain((i32::MIN..=i32::MAX).step_by(65_521))
1033 .chain(i32::MAX - 2000..=i32::MAX)
1034 }
1035
1036 #[test]
1037 fn shortest_sampled_fixed() {
1038 check_all!(Fixed, sampled_i32());
1039 }
1040
1041 #[test]
1042 fn shortest_sampled_f26dot6() {
1043 check_all!(F26Dot6, sampled_i32());
1044 }
1045
1046 #[test]
1047 fn formatter_flags() {
1048 let value = F2Dot14(9830);
1049 assert_eq!(format!("{value:.2}"), "0.60");
1050 assert_eq!(format!("{value:.2?}"), "0.60");
1051 assert_eq!(format!("{value:>8}"), " 0.6");
1052 assert_eq!(format!("{value:8}"), " 0.6");
1053 assert_eq!(format!("{value:<8}|"), "0.6 |");
1054 assert_eq!(format!("{value:*^9}"), "***0.6***");
1055 assert_eq!(format!("{value:08}"), "000000.6");
1056 assert_eq!(format!("{value:+}"), "+0.6");
1057 assert_eq!(format!("{value:?}"), "0.6");
1058 for (value, float) in [(F2Dot14::from_f32(-1.5), -1.5f64), (F2Dot14::ONE, 1.0)] {
1061 assert_eq!(format!("{value}"), format!("{float}"));
1062 assert_eq!(format!("{value:.3}"), format!("{float:.3}"));
1063 assert_eq!(format!("{value:>8}"), format!("{float:>8}"));
1064 assert_eq!(format!("{value:<8}"), format!("{float:<8}"));
1065 assert_eq!(format!("{value:08}"), format!("{float:08}"));
1066 assert_eq!(format!("{value:+09}"), format!("{float:+09}"));
1067 }
1068 }
1069 }
1070
1071 #[cfg(feature = "serde")]
1072 mod serde {
1073 use super::*;
1074
1075 macro_rules! roundtrip_one {
1076 ($fixed:ident) => {{
1077 let before = <$fixed>::ONE;
1078 let serialized = ::serde_json::to_string(&before).expect("should serialize");
1079 assert_eq!(&serialized, "1.0");
1080 let after = ::serde_json::from_str(&serialized).expect("should deserialize");
1081 assert_eq!(before, after);
1082 }};
1083 }
1084
1085 #[test]
1086 fn one_is_one_f2dot14() {
1087 roundtrip_one!(F2Dot14);
1088 }
1089
1090 #[test]
1091 fn one_is_one_f4dot12() {
1092 roundtrip_one!(F4Dot12);
1093 }
1094
1095 #[test]
1096 fn one_is_one_f6dot10() {
1097 roundtrip_one!(F6Dot10);
1098 }
1099
1100 #[test]
1101 fn one_is_one_fixed() {
1102 roundtrip_one!(Fixed);
1103 }
1104
1105 #[test]
1106 fn one_is_one_f26dot6() {
1107 roundtrip_one!(F26Dot6);
1108 }
1109
1110 macro_rules! roundtrip_all {
1111 ($fixed:ident, $ty:ty) => {
1112 for raw in <$ty>::MIN..=<$ty>::MAX {
1113 let fixed = $fixed(raw);
1114 let fixed_float = fixed.to_f64();
1115
1116 let json_value = ::serde_json::to_value(&fixed).expect("should serialize");
1117 let json_float = json_value
1118 .as_f64()
1119 .expect("serde didn't serialize the value to a float");
1120
1121 assert_eq!(
1125 fixed_float,
1126 json_float,
1127 "failed on {raw} ({fixed_type}({raw:#X})): {json_float} != {fixed_float}",
1128 fixed_type = ::std::stringify!($fixed),
1129 );
1130 }
1131 };
1132 }
1133
1134 #[test]
1135 fn roundtrip_all_f2dot14() {
1136 roundtrip_all!(F2Dot14, i16);
1137 }
1138
1139 #[test]
1140 fn roundtrip_all_f4dot12() {
1141 roundtrip_all!(F4Dot12, i16);
1142 }
1143
1144 #[test]
1145 fn roundtrip_all_f6dot10() {
1146 roundtrip_all!(F6Dot10, i16);
1147 }
1148
1149 #[test]
1150 #[ignore = "enumerating all i32 values takes a while"]
1151 fn roundtrip_all_fixed() {
1152 roundtrip_all!(Fixed, i32);
1153 }
1154
1155 #[test]
1156 #[ignore = "enumerating all i32 values takes a while"]
1157 fn roundtrip_all_f26dot6() {
1158 roundtrip_all!(F26Dot6, i32);
1159 }
1160 }
1161}