use core::ops::{Add, AddAssign, Mul, Neg, Shl, Shr, Sub, SubAssign};
use fixed::traits::{Fixed, FixedSigned};
use fixed::types::extra::{IsLessOrEqual, LeEqU128, True, Unsigned};
use fixed::{FixedI8, FixedI16, FixedI32, FixedI64, FixedI128};
pub trait CordicNumber:
Copy
+ PartialEq
+ PartialOrd
+ Add<Output = Self>
+ Sub<Output = Self>
+ Mul<Output = Self>
+ Neg<Output = Self>
+ AddAssign
+ SubAssign
+ Shl<u32, Output = Self>
+ Shr<u32, Output = Self>
{
fn zero() -> Self;
fn one() -> Self;
#[must_use]
fn two() -> Self {
Self::one() + Self::one()
}
#[must_use]
fn half() -> Self {
Self::from_num(0.5)
}
fn pi() -> Self;
fn frac_pi_2() -> Self;
#[must_use]
fn frac_pi_4() -> Self {
Self::frac_pi_2() >> 1
}
fn e() -> Self;
fn ln_2() -> Self;
fn ln_10() -> Self;
#[must_use]
fn abs(self) -> Self;
fn frac_bits() -> u32;
fn total_bits() -> u32;
fn from_i1f63(bits: i64) -> Self;
fn is_negative(self) -> bool;
fn is_positive(self) -> bool {
!self.is_negative() && self != Self::zero()
}
#[must_use]
fn saturating_mul(self, rhs: Self) -> Self;
#[must_use]
fn saturating_add(self, rhs: Self) -> Self;
#[must_use]
fn saturating_sub(self, rhs: Self) -> Self;
#[must_use]
fn div(self, rhs: Self) -> Self;
fn from_num<N: fixed::traits::ToFixed>(n: N) -> Self;
fn max_value() -> Self;
fn min_value() -> Self;
#[must_use]
fn round(self) -> Self;
#[must_use]
fn to_i32(self) -> i32;
}
macro_rules! impl_cordic_generic {
(
$fixed_type:ident,
$bits_type:ty,
$total_bits:expr,
$max_frac:ty, // Maximum fractional bits for the type
$pi_frac:ty, // Max frac bits where PI fits (total - 2)
$frac_pi_2:ty, $frac_pi_4:ty ) => {
impl<Fract> CordicNumber for $fixed_type<Fract>
where
Fract: Unsigned
+ IsLessOrEqual<$max_frac, Output = True>
+ IsLessOrEqual<$pi_frac, Output = True>
+ IsLessOrEqual<$frac_pi_2, Output = True>
+ IsLessOrEqual<$frac_pi_4, Output = True>
+ LeEqU128,
{
#[inline]
fn zero() -> Self {
Self::ZERO
}
#[inline]
fn one() -> Self {
Self::ONE
}
#[inline]
fn pi() -> Self {
Self::PI
}
#[inline]
fn frac_pi_2() -> Self {
Self::FRAC_PI_2
}
#[inline]
fn e() -> Self {
Self::E
}
#[inline]
fn ln_2() -> Self {
Self::LN_2
}
#[inline]
fn ln_10() -> Self {
Self::LN_10
}
#[inline]
fn abs(self) -> Self {
FixedSigned::saturating_abs(self)
}
#[inline]
fn frac_bits() -> u32 {
Self::FRAC_NBITS
}
#[inline]
fn total_bits() -> u32 {
$total_bits
}
#[inline]
#[allow(
clippy::cast_possible_wrap,
clippy::cast_lossless,
reason = "frac_bits bounded by type size"
)]
fn from_i1f63(bits: i64) -> Self {
let our_frac = Self::FRAC_NBITS as i32;
let shift = 63 - our_frac;
if shift >= 0 {
#[allow(
clippy::cast_possible_truncation,
reason = "intentional truncation to target type"
)]
Self::from_bits((bits >> shift) as $bits_type)
} else {
#[allow(
clippy::cast_possible_truncation,
reason = "intentional truncation to target type"
)]
let wide = bits as $bits_type;
Self::from_bits(wide << (-shift))
}
}
#[inline]
fn is_negative(self) -> bool {
self < Self::ZERO
}
#[inline]
fn saturating_mul(self, rhs: Self) -> Self {
Fixed::saturating_mul(self, rhs)
}
#[inline]
fn saturating_add(self, rhs: Self) -> Self {
Fixed::saturating_add(self, rhs)
}
#[inline]
fn saturating_sub(self, rhs: Self) -> Self {
Fixed::saturating_sub(self, rhs)
}
#[inline]
fn div(self, rhs: Self) -> Self {
match Fixed::checked_div(self, rhs) {
Some(v) => v,
None => {
if self.is_negative() != rhs.is_negative() {
Self::MIN
} else {
Self::MAX
}
}
}
}
#[inline]
fn from_num<N: fixed::traits::ToFixed>(n: N) -> Self {
Self::from_num(n)
}
#[inline]
fn max_value() -> Self {
Self::MAX
}
#[inline]
fn min_value() -> Self {
Self::MIN
}
#[inline]
fn round(self) -> Self {
Fixed::round(self)
}
#[inline]
#[allow(
clippy::cast_possible_truncation,
reason = "intentional truncation to target type"
)]
fn to_i32(self) -> i32 {
self.to_num::<i32>()
}
}
};
}
use fixed::types::extra::{
U5, U6, U7, U8, U13, U14, U15, U16, U29, U30, U31, U32, U61, U62, U63, U64, U125, U126, U127,
U128,
};
impl_cordic_generic!(FixedI8, i8, 8, U8, U5, U6, U7);
impl_cordic_generic!(FixedI16, i16, 16, U16, U13, U14, U15);
impl_cordic_generic!(FixedI32, i32, 32, U32, U29, U30, U31);
impl_cordic_generic!(FixedI64, i64, 64, U64, U61, U62, U63);
impl_cordic_generic!(FixedI128, i128, 128, U128, U125, U126, U127);