1use fixed::types::I32F32;
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5use std::fmt;
6use std::iter::Sum;
7use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
8use std::str::FromStr;
9
10pub const PPM_SCALE: u32 = 1_000_000;
12
13#[derive(Debug, Clone, PartialEq, Eq)]
15pub enum FixedQ32Error {
16 Overflow,
18 DivisionByZero,
20}
21
22impl fmt::Display for FixedQ32Error {
23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 match self {
25 Self::Overflow => write!(f, "fixed-point overflow"),
26 Self::DivisionByZero => write!(f, "fixed-point division by zero"),
27 }
28 }
29}
30
31impl std::error::Error for FixedQ32Error {}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
37pub struct FixedQ32(I32F32);
38
39impl FixedQ32 {
40 pub const FRACTIONAL_BITS: u32 = 32;
42 pub const SCALE: i64 = 1_i64 << Self::FRACTIONAL_BITS;
44
45 #[must_use]
47 pub const fn from_bits(bits: i64) -> Self {
48 Self(I32F32::from_bits(bits))
49 }
50
51 #[must_use]
53 pub const fn to_bits(self) -> i64 {
54 self.0.to_bits()
55 }
56
57 #[must_use]
59 pub const fn zero() -> Self {
60 Self::from_bits(0)
61 }
62
63 #[must_use]
65 pub const fn one() -> Self {
66 Self::from_bits(Self::SCALE)
67 }
68
69 #[must_use]
71 pub const fn neg_one() -> Self {
72 Self::from_bits(-Self::SCALE)
73 }
74
75 #[must_use]
77 pub fn half() -> Self {
78 Self::from_bits(Self::SCALE / 2)
79 }
80
81 pub fn try_from_i64(value: i64) -> Result<Self, FixedQ32Error> {
87 I32F32::checked_from_num(value)
88 .map(Self)
89 .ok_or(FixedQ32Error::Overflow)
90 }
91
92 pub fn try_from_u64(value: u64) -> Result<Self, FixedQ32Error> {
98 I32F32::checked_from_num(value)
99 .map(Self)
100 .ok_or(FixedQ32Error::Overflow)
101 }
102
103 pub fn try_from_usize(value: usize) -> Result<Self, FixedQ32Error> {
109 I32F32::checked_from_num(value)
110 .map(Self)
111 .ok_or(FixedQ32Error::Overflow)
112 }
113
114 pub fn from_ratio(num: i64, den: i64) -> Result<Self, FixedQ32Error> {
121 if den == 0 {
122 return Err(FixedQ32Error::DivisionByZero);
123 }
124 let n = I32F32::checked_from_num(num).ok_or(FixedQ32Error::Overflow)?;
125 let d = I32F32::checked_from_num(den).ok_or(FixedQ32Error::Overflow)?;
126 n.checked_div(d).map(Self).ok_or(FixedQ32Error::Overflow)
127 }
128
129 pub fn from_ppm(ppm: u32) -> Result<Self, FixedQ32Error> {
137 let n = I32F32::checked_from_num(ppm).ok_or(FixedQ32Error::Overflow)?;
138 let d = I32F32::checked_from_num(PPM_SCALE).ok_or(FixedQ32Error::Overflow)?;
139 n.checked_div(d).map(Self).ok_or(FixedQ32Error::Overflow)
140 }
141
142 pub fn from_decimal_str(s: &str) -> Result<Self, FixedQ32Error> {
148 s.parse::<I32F32>()
149 .map(Self)
150 .map_err(|_| FixedQ32Error::Overflow)
151 }
152
153 #[must_use]
155 pub fn checked_add(self, rhs: Self) -> Option<Self> {
156 self.0.checked_add(rhs.0).map(Self)
157 }
158
159 #[must_use]
161 pub fn checked_sub(self, rhs: Self) -> Option<Self> {
162 self.0.checked_sub(rhs.0).map(Self)
163 }
164
165 #[must_use]
167 pub fn checked_mul(self, rhs: Self) -> Option<Self> {
168 self.0.checked_mul(rhs.0).map(Self)
169 }
170
171 #[must_use]
173 pub fn checked_div(self, rhs: Self) -> Option<Self> {
174 self.0.checked_div(rhs.0).map(Self)
175 }
176
177 #[must_use]
179 pub fn saturating_add(self, rhs: Self) -> Self {
180 Self(self.0.saturating_add(rhs.0))
181 }
182
183 #[must_use]
185 pub fn saturating_sub(self, rhs: Self) -> Self {
186 Self(self.0.saturating_sub(rhs.0))
187 }
188
189 #[must_use]
191 pub fn saturating_mul(self, rhs: Self) -> Self {
192 Self(self.0.saturating_mul(rhs.0))
193 }
194
195 #[must_use]
197 pub fn saturating_div(self, rhs: Self) -> Self {
198 Self(self.0.saturating_div(rhs.0))
199 }
200
201 #[must_use]
203 pub fn saturating_mul_int(self, rhs: i64) -> Self {
204 Self(self.0.saturating_mul_int(rhs))
205 }
206
207 #[must_use]
209 pub fn saturating_div_int(self, rhs: i64) -> Self {
210 Self(self.0.saturating_div_int(rhs))
211 }
212
213 #[must_use]
215 pub fn floor(self) -> Self {
216 Self(self.0.floor())
217 }
218
219 #[must_use]
221 pub fn ceil(self) -> Self {
222 Self(self.0.ceil())
223 }
224
225 #[must_use]
227 pub fn round(self) -> Self {
228 Self(self.0.round())
229 }
230
231 #[must_use]
233 pub fn abs(self) -> Self {
234 Self(self.0.abs())
235 }
236
237 #[must_use]
239 pub fn clamp(self, lo: Self, hi: Self) -> Self {
240 if self < lo {
241 lo
242 } else if self > hi {
243 hi
244 } else {
245 self
246 }
247 }
248
249 #[must_use]
251 pub fn min(self, rhs: Self) -> Self {
252 if self <= rhs {
253 self
254 } else {
255 rhs
256 }
257 }
258
259 #[must_use]
261 pub fn max(self, rhs: Self) -> Self {
262 if self >= rhs {
263 self
264 } else {
265 rhs
266 }
267 }
268
269 #[must_use]
271 pub fn is_positive(self) -> bool {
272 self > Self::zero()
273 }
274
275 #[must_use]
277 pub fn is_negative(self) -> bool {
278 self < Self::zero()
279 }
280
281 #[must_use]
283 pub fn square(self) -> Self {
284 self.saturating_mul(self)
285 }
286
287 #[must_use]
289 pub fn powi(self, exp: u32) -> Self {
290 let mut out = Self::one();
291 for _ in 0..exp {
292 out = out.saturating_mul(self);
293 }
294 out
295 }
296
297 #[must_use]
299 pub fn sqrt(self) -> Self {
300 if self <= Self::zero() {
301 return Self::zero();
302 }
303 let two = Self::from_bits(2 * Self::SCALE);
305 let mut x = self.max(Self::one());
306 for _ in 0..16 {
307 let q = self.saturating_div(x);
308 x = x.saturating_add(q).saturating_div(two);
309 }
310 x
311 }
312
313 #[must_use]
317 pub fn tanh_approx(self) -> Self {
318 let one = Self::one();
319 let three = Self::from_bits(3 * Self::SCALE);
320 if self >= three {
321 return one;
322 }
323 if self <= -three {
324 return -one;
325 }
326 let nine = Self::from_bits(9 * Self::SCALE);
327 let twenty_seven = Self::from_bits(27 * Self::SCALE);
328 let x2 = self.square();
329 let num = self.saturating_mul(twenty_seven.saturating_add(x2));
330 let den = twenty_seven.saturating_add(nine.saturating_mul(x2));
331 num.saturating_div(den).clamp(-one, one)
332 }
333
334 #[must_use]
336 pub fn tanh(self) -> Self {
337 self.tanh_approx()
338 }
339
340 #[must_use]
342 pub const fn is_finite(self) -> bool {
343 let _ = self;
345 true
346 }
347
348 pub fn to_i64_floor(self) -> Result<i64, FixedQ32Error> {
354 self.floor()
355 .0
356 .checked_to_num()
357 .ok_or(FixedQ32Error::Overflow)
358 }
359
360 pub fn to_i64_ceil(self) -> Result<i64, FixedQ32Error> {
366 self.ceil()
367 .0
368 .checked_to_num()
369 .ok_or(FixedQ32Error::Overflow)
370 }
371
372 pub fn to_i64_round(self) -> Result<i64, FixedQ32Error> {
378 self.round()
379 .0
380 .checked_to_num()
381 .ok_or(FixedQ32Error::Overflow)
382 }
383
384 pub fn to_usize_round(self) -> Result<usize, FixedQ32Error> {
390 let i = self.to_i64_round()?;
391 if i < 0 {
392 return Err(FixedQ32Error::Overflow);
393 }
394 usize::try_from(i).map_err(|_| FixedQ32Error::Overflow)
395 }
396
397 pub fn to_u64_round(self) -> Result<u64, FixedQ32Error> {
403 let i = self.to_i64_round()?;
404 if i < 0 {
405 return Err(FixedQ32Error::Overflow);
406 }
407 u64::try_from(i).map_err(|_| FixedQ32Error::Overflow)
408 }
409}
410
411impl fmt::Display for FixedQ32 {
412 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
413 write!(f, "{}", self.0)
414 }
415}
416
417impl Serialize for FixedQ32 {
418 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
419 where
420 S: Serializer,
421 {
422 serializer.serialize_i64(self.to_bits())
423 }
424}
425
426impl<'de> Deserialize<'de> for FixedQ32 {
427 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
428 where
429 D: Deserializer<'de>,
430 {
431 struct FixedQ32Visitor;
432
433 impl<'de> serde::de::Visitor<'de> for FixedQ32Visitor {
434 type Value = FixedQ32;
435
436 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
437 formatter.write_str(
438 "a fixed-point number encoded as raw bits (i64/u64) or decimal string",
439 )
440 }
441
442 fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
443 where
444 E: serde::de::Error,
445 {
446 Ok(FixedQ32::from_bits(v))
447 }
448
449 fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
450 where
451 E: serde::de::Error,
452 {
453 let bits = i64::try_from(v).map_err(|_| E::custom(FixedQ32Error::Overflow))?;
454 Ok(FixedQ32::from_bits(bits))
455 }
456
457 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
458 where
459 E: serde::de::Error,
460 {
461 FixedQ32::from_decimal_str(v).map_err(E::custom)
462 }
463
464 fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
465 where
466 E: serde::de::Error,
467 {
468 self.visit_str(&v)
469 }
470 }
471
472 deserializer.deserialize_any(FixedQ32Visitor)
473 }
474}
475
476impl TryFrom<i64> for FixedQ32 {
477 type Error = FixedQ32Error;
478
479 fn try_from(value: i64) -> Result<Self, Self::Error> {
480 Self::try_from_i64(value)
481 }
482}
483
484impl TryFrom<u64> for FixedQ32 {
485 type Error = FixedQ32Error;
486
487 fn try_from(value: u64) -> Result<Self, Self::Error> {
488 Self::try_from_u64(value)
489 }
490}
491
492impl From<f64> for FixedQ32 {
493 fn from(value: f64) -> Self {
494 I32F32::checked_from_num(value)
495 .map(Self)
496 .unwrap_or_else(|| {
497 if value.is_sign_negative() {
498 Self(I32F32::MIN)
499 } else {
500 Self(I32F32::MAX)
501 }
502 })
503 }
504}
505
506impl TryFrom<usize> for FixedQ32 {
507 type Error = FixedQ32Error;
508
509 fn try_from(value: usize) -> Result<Self, Self::Error> {
510 Self::try_from_usize(value)
511 }
512}
513
514impl TryFrom<FixedQ32> for i64 {
515 type Error = FixedQ32Error;
516
517 fn try_from(value: FixedQ32) -> Result<Self, Self::Error> {
518 value.to_i64_round()
519 }
520}
521
522impl TryFrom<FixedQ32> for u64 {
523 type Error = FixedQ32Error;
524
525 fn try_from(value: FixedQ32) -> Result<Self, Self::Error> {
526 let i = value.to_i64_round()?;
527 if i < 0 {
528 return Err(FixedQ32Error::Overflow);
529 }
530 u64::try_from(i).map_err(|_| FixedQ32Error::Overflow)
531 }
532}
533
534impl Add for FixedQ32 {
535 type Output = Self;
536
537 fn add(self, rhs: Self) -> Self::Output {
538 self.saturating_add(rhs)
539 }
540}
541
542impl AddAssign for FixedQ32 {
543 fn add_assign(&mut self, rhs: Self) {
544 *self = self.saturating_add(rhs);
545 }
546}
547
548impl Sub for FixedQ32 {
549 type Output = Self;
550
551 fn sub(self, rhs: Self) -> Self::Output {
552 self.saturating_sub(rhs)
553 }
554}
555
556impl SubAssign for FixedQ32 {
557 fn sub_assign(&mut self, rhs: Self) {
558 *self = self.saturating_sub(rhs);
559 }
560}
561
562impl Mul for FixedQ32 {
563 type Output = Self;
564
565 fn mul(self, rhs: Self) -> Self::Output {
566 self.saturating_mul(rhs)
567 }
568}
569
570impl MulAssign for FixedQ32 {
571 fn mul_assign(&mut self, rhs: Self) {
572 *self = self.saturating_mul(rhs);
573 }
574}
575
576impl Div for FixedQ32 {
577 type Output = Self;
578
579 fn div(self, rhs: Self) -> Self::Output {
580 self.saturating_div(rhs)
581 }
582}
583
584impl DivAssign for FixedQ32 {
585 fn div_assign(&mut self, rhs: Self) {
586 *self = self.saturating_div(rhs);
587 }
588}
589
590impl Neg for FixedQ32 {
591 type Output = Self;
592
593 fn neg(self) -> Self::Output {
594 Self::zero().saturating_sub(self)
595 }
596}
597
598include!("fixed_q32/iter_and_parse_impls.rs");
599
600#[cfg(test)]
601mod tests {
602 include!("fixed_q32/tests.rs");
603}