1#![cfg_attr(not(feature = "std"), no_std)]
2#![doc = include_str!("../README.md")]
3
4mod format;
5mod num_traits_impl;
6mod ops;
7#[cfg(feature = "serde")]
8pub mod serde;
9
10use num_traits::{AsPrimitive, ConstOne, One};
11
12use core::{
13 hash::{Hash, Hasher},
14 marker::PhantomData,
15 num::Wrapping,
16 ops::{Div, Mul, Shl, Shr},
17};
18
19pub(crate) trait AsFloat: Copy {
21 fn as_f32(self) -> f32;
22 fn as_f64(self) -> f64;
23}
24
25macro_rules! impl_as_float {
26 ($($ty:ty),* $(,)?) => {
27 $(
28 impl AsFloat for $ty {
29 #[inline]
30 fn as_f32(self) -> f32 {
31 self as f32
32 }
33
34 #[inline]
35 fn as_f64(self) -> f64 {
36 self as f64
37 }
38 }
39
40 impl AsFloat for Wrapping<$ty> {
41 #[inline]
42 fn as_f32(self) -> f32 {
43 self.0 as f32
44 }
45
46 #[inline]
47 fn as_f64(self) -> f64 {
48 self.0 as f64
49 }
50 }
51 )*
52 };
53}
54
55impl_as_float!(i8, i16, i32, i64, u8, u16, u32, u64);
56
57pub trait Shift: Copy + Shl<usize, Output = Self> + Shr<usize, Output = Self> {
61 fn shs(self, f: i8) -> Self;
71
72 #[inline(always)]
74 fn shsc<const F: i8>(self) -> Self {
75 const { assert!(F > i8::MIN, "shift must not be i8::MIN") }
76 self.shs(F)
77 }
78}
79
80impl<T: Copy + Shl<usize, Output = T> + Shr<usize, Output = T>> Shift for T {
81 #[inline(always)]
82 fn shs(self, f: i8) -> Self {
83 debug_assert!(f > i8::MIN, "shift must not be i8::MIN");
84 if f >= 0 {
85 self << (f as _)
86 } else {
87 self >> (-f as _)
88 }
89 }
90}
91
92pub trait Accu<A> {
94 fn up(self) -> A;
103
104 fn down(a: A) -> Self;
113
114 }
123
124#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
146#[derive(Default)]
147#[repr(transparent)]
148#[cfg_attr(feature = "serde", serde(transparent))]
149#[cfg_attr(
150 feature = "bytemuck",
151 derive(bytemuck::Pod, bytemuck::TransparentWrapper, bytemuck::Zeroable),
152 transparent(T)
153)]
154#[must_use]
155pub struct Q<T, A, const F: i8> {
156 _accu: PhantomData<A>,
158 inner: T,
160}
161
162impl<T: Clone, A, const F: i8> Clone for Q<T, A, F> {
163 #[inline]
164 fn clone(&self) -> Self {
165 Self {
166 _accu: PhantomData,
167 inner: self.inner.clone(),
168 }
169 }
170}
171
172impl<T: Copy, A, const F: i8> Copy for Q<T, A, F> {}
173
174impl<T: PartialEq, A, const F: i8> PartialEq for Q<T, A, F> {
175 #[inline]
176 fn eq(&self, other: &Self) -> bool {
177 self.inner.eq(&other.inner)
178 }
179}
180
181impl<T: Eq, A, const F: i8> Eq for Q<T, A, F> where Self: PartialEq {}
182
183impl<T: Hash, A, const F: i8> Hash for Q<T, A, F> {
184 #[inline]
185 fn hash<H: Hasher>(&self, state: &mut H) {
186 self.inner.hash(state)
187 }
188}
189
190impl<T: PartialOrd, A, const F: i8> PartialOrd for Q<T, A, F> {
191 #[inline]
192 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
193 self.inner.partial_cmp(&other.inner)
194 }
195}
196
197impl<T: Ord, A, const F: i8> Ord for Q<T, A, F>
198where
199 Self: PartialOrd,
200{
201 #[inline]
202 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
203 self.inner.cmp(&other.inner)
204 }
205}
206
207impl<T, A, const F: i8> Q<T, A, F> {
208 pub const DELTA: f32 = if F > 0 {
221 1.0 / (1u128 << F) as f32
222 } else {
223 (1u128 << -F) as f32
224 };
225
226 #[inline]
227 const fn new(inner: T) -> Self {
228 Self {
229 _accu: PhantomData,
230 inner,
231 }
232 }
233
234 #[inline]
236 pub const fn from_bits(bits: T) -> Self {
237 Self::new(bits)
238 }
239
240 #[inline]
242 #[must_use]
243 pub fn into_bits(self) -> T {
244 self.inner
245 }
246}
247
248impl<T: Shift, A, const F: i8> Q<T, A, F> {
249 #[inline]
258 pub fn scale<const F1: i8>(self) -> Q<T, A, F1> {
259 Q::new(self.inner.shs(const { F1 - F }))
260 }
261
262 #[inline]
269 #[must_use]
270 pub fn trunc(self) -> T {
271 self.inner.shs(const { -F })
272 }
273
274 #[inline]
281 pub fn from_int(value: T) -> Self {
282 Self::new(value.shsc::<F>())
283 }
284}
285
286impl<A: Shift, T: Accu<A>, const F: i8> Q<A, T, F> {
287 #[inline]
296 #[must_use]
297 pub fn quantize(self) -> T {
298 T::down(self.trunc())
299 }
300}
301
302impl<T: Accu<A>, A: Mul<Output = A>, const F: i8> Q<T, A, F> {
303 #[inline]
310 pub fn mul_wide(self, rhs: T) -> Q<A, T, F> {
311 Q::new(self.inner.up() * rhs.up())
312 }
313}
314
315impl<T: Accu<A>, A: Shift + Mul<Output = A>, const F: i8> Q<T, A, F> {
316 #[inline]
323 #[must_use]
324 pub fn apply(self, rhs: T) -> T {
325 self.mul_wide(rhs).quantize()
326 }
327}
328
329impl<T: Accu<A> + Shift, A, const F: i8> From<(T, i8)> for Q<T, A, F> {
336 fn from(value: (T, i8)) -> Self {
337 Self::new(value.0.shs(F - value.1))
338 }
339}
340
341impl<T, A, const F: i8> From<Q<T, A, F>> for (T, i8) {
349 fn from(value: Q<T, A, F>) -> Self {
350 (value.inner, F)
351 }
352}
353
354impl<T, A, const F: i8> Q<T, A, F>
355where
356 f32: AsPrimitive<Q<T, A, F>>,
357 Self: Copy + 'static,
358{
359 #[inline]
361 pub fn from_f32(value: f32) -> Self {
362 value.as_()
363 }
364}
365
366impl<T, A, const F: i8> Q<T, A, F>
367where
368 f64: AsPrimitive<Q<T, A, F>>,
369 Self: Copy + 'static,
370{
371 #[inline]
373 pub fn from_f64(value: f64) -> Self {
374 value.as_()
375 }
376}
377
378#[allow(private_bounds)]
379impl<T: AsFloat, A, const F: i8> Q<T, A, F> {
380 #[inline]
382 #[must_use]
383 pub fn as_f32(self) -> f32 {
384 self.inner.as_f32() * Self::DELTA
385 }
386
387 #[inline]
389 #[must_use]
390 pub fn as_f64(self) -> f64 {
391 self.inner.as_f64() * Self::DELTA as f64
392 }
393}
394
395macro_rules! impl_q {
396 ($alias:ident<$t:ty, $a:ty>) => {
398 impl_q!($alias<$t, $a>, $t, |x| x as _, core::convert::identity);
399 };
400 ($alias:ident<$t:ty, $a:ty>, $wrap:tt) => {
402 impl_q!($alias<$wrap<$t>, $wrap<$a>>, $t, |x: $wrap<_>| $wrap(x.0 as _), $wrap);
403 };
404 ($alias:ident<$t:ty, $a:ty>, $inner:ty, $as:expr, $wrap:expr) => {
406 impl Accu<$a> for $t {
407 #[inline(always)]
408 fn up(self) -> $a {
409 $as(self)
410 }
411 #[inline(always)]
412 fn down(a: $a) -> Self {
413 $as(a)
414 }
415 }
416
417 #[doc = concat!("Fixed point [`", stringify!($t), "`] with [`", stringify!($a), "`] accumulator")]
418 pub type $alias<const F: i8> = Q<$t, $a, F>;
419
420 impl<const F: i8> ConstOne for Q<$t, $a, F> {
421 const ONE: Self = {
422 const {
423 const MAX_ONE_F: i8 =
424 <$inner>::BITS as i8 - if <$inner>::MIN == 0 { 0 } else { 1 };
425 assert!(
426 F >= 0 && F < MAX_ONE_F,
427 "`Q::ONE` is only available when 1 is exactly representable"
428 );
429 }
430 Self::new($wrap(1 << F as usize))
431 };
432 }
433
434 impl<const F: i8> One for Q<$t, $a, F> {
435 fn one() -> Self {
436 const {
437 const MAX_ONE_F: i8 =
438 <$inner>::BITS as i8 - if <$inner>::MIN == 0 { 0 } else { 1 };
439 assert!(
440 F >= 0 && F < MAX_ONE_F,
441 "`Q::one()` is only available when 1 is exactly representable"
442 );
443 }
444 Self::ONE
445 }
446 }
447
448 impl<const F: i8> Mul<Q<$t, $a, F>> for $t {
450 type Output = $t;
451
452 #[inline]
453 fn mul(self, rhs: Q<$t, $a, F>) -> Self::Output {
454 rhs.apply(self)
455 }
456 }
457
458 impl<const F: i8> Div<Q<$t, $a, F>> for $t {
460 type Output = $t;
461
462 #[inline]
463 fn div(self, rhs: Q<$t, $a, F>) -> Self::Output {
464 if F > 0 {
465 <$t>::down(self.up().shs(F) / rhs.inner.up())
466 } else {
467 self.shsc::<F>() / rhs.inner
468 }
469 }
470 }
471 };
472}
473impl_q!(Q8<i8, i16>);
475impl_q!(Q16<i16, i32>);
476impl_q!(Q32<i32, i64>);
477impl_q!(Q64<i64, i128>);
478impl_q!(P8<u8, u16>);
480impl_q!(P16<u16, u32>);
481impl_q!(P32<u32, u64>);
482impl_q!(P64<u64, u128>);
483impl_q!(W8<i8, i16>, Wrapping);
485impl_q!(W16<i16, i32>, Wrapping);
486impl_q!(W32<i32, i64>, Wrapping);
487impl_q!(W64<i64, i128>, Wrapping);
488impl_q!(V8<u8, u16>, Wrapping);
490impl_q!(V16<u16, u32>, Wrapping);
491impl_q!(V32<u32, u64>, Wrapping);
492impl_q!(V64<u64, u128>, Wrapping);
493
494#[cfg(test)]
497mod test {
498 use super::*;
499 use num_traits::{Bounded, FromPrimitive, Signed, ToPrimitive};
500
501 #[test]
502 fn simple() {
503 assert_eq!(
504 Q32::<5>::from_int(4) * Q32::<5>::from_int(3),
505 Q32::from_int(3 * 4)
506 );
507 assert_eq!(
508 Q32::<5>::from_int(12) / Q32::<5>::from_int(6),
509 Q32::from_int(2)
510 );
511 assert_eq!(7 * Q32::<4>::from_bits(0x33), 7 * 3 + ((3 * 7) >> 4));
512 assert_eq!(Q32::<4>::from_bits(0x33).apply(7), 7 * 3 + ((3 * 7) >> 4));
513 assert_eq!(
514 Q32::<4>::from_bits(0x33).mul_wide(7).quantize(),
515 7 * Q32::<4>::from_bits(0x33)
516 );
517 }
518
519 #[test]
520 fn numeric_traits() {
521 assert_eq!(Q8::<4>::min_value().into_bits(), i8::MIN);
522 assert_eq!(Q8::<4>::max_value().into_bits(), i8::MAX);
523 assert_eq!(Q8::<4>::from_f32(1.5).to_i32(), Some(1));
524 assert_eq!(Q8::<4>::from_f32(1.5).to_f64(), Some(1.5));
525 assert_eq!(Q8::<4>::from_i32(3), Some(Q8::<4>::from_int(3)));
526 assert_eq!(Q8::<4>::from_f32(-1.5).abs(), Q8::<4>::from_f32(1.5));
527 assert_eq!(Q8::<4>::from_f32(-1.5).signum(), Q8::<4>::from_int(-1));
528 assert!(Q8::<4>::from_f32(-1.5).is_negative());
529 }
530
531 #[cfg(feature = "bytemuck")]
532 #[test]
533 fn bytemuck_traits() {
534 use bytemuck::TransparentWrapper;
535
536 let q = Q8::<4>::from_int(3);
537 assert_eq!(q.into_bits(), 48);
538 assert_eq!(Q8::<4>::wrap(48i8), q);
539 assert_eq!(*Q8::<4>::wrap_ref(&48i8), q);
540 }
541}