Compare commits
7 Commits
divide-tra
...
wide-mul
| Author | SHA1 | Date | |
|---|---|---|---|
| 14cec421e0 | |||
| fb9228b7fd | |||
| 3f0900b0ec | |||
| 658c73a033 | |||
| b98eba27e5 | |||
| 503f5b6d22 | |||
| f22cd653df |
5
fixed_wide/Cargo.lock
generated
5
fixed_wide/Cargo.lock
generated
@@ -21,7 +21,6 @@ dependencies = [
|
||||
"arrayvec",
|
||||
"bnum",
|
||||
"paste",
|
||||
"ratio_ops",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -29,7 +28,3 @@ name = "paste"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "ratio_ops"
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -4,13 +4,12 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
default=[]
|
||||
deferred-division=["dep:ratio_ops"]
|
||||
default=["zeroes","wide-mul"]
|
||||
ratio=[]
|
||||
wide-mul=[]
|
||||
zeroes=["dep:arrayvec"]
|
||||
zeroes=["ratio","dep:arrayvec"]
|
||||
|
||||
[dependencies]
|
||||
bnum = "0.11.0"
|
||||
arrayvec = { version = "0.7.6", optional = true }
|
||||
paste = "1.0.15"
|
||||
ratio_ops = { path = "../ratio_ops", optional = true }
|
||||
|
||||
@@ -33,17 +33,6 @@ impl<const N:usize,const F:usize> Fixed<N,F>{
|
||||
self.bits
|
||||
}
|
||||
#[inline]
|
||||
pub const fn raw_digit(value:i64)->Self{
|
||||
let mut digits=[0u64;N];
|
||||
digits[0]=value.abs() as u64;
|
||||
//sign bit
|
||||
digits[N-1]|=(value&i64::MIN) as u64;
|
||||
Self::from_bits(BInt::from_bits(bnum::BUint::from_digits(digits)))
|
||||
}
|
||||
}
|
||||
impl<const F:usize> Fixed<1,F>{
|
||||
/// My old code called this function everywhere so let's provide it
|
||||
#[inline]
|
||||
pub const fn raw(value:i64)->Self{
|
||||
Self::from_bits(BInt::from_bits(bnum::BUint::from_digit(value as u64)))
|
||||
}
|
||||
@@ -53,48 +42,24 @@ impl<const N:usize,const F:usize,T> From<T> for Fixed<N,F>
|
||||
where
|
||||
BInt<N>:From<T>
|
||||
{
|
||||
#[inline]
|
||||
fn from(value:T)->Self{
|
||||
Self::from_bits(BInt::<{N}>::from(value)<<F as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N:usize,const F:usize> PartialEq for Fixed<N,F>{
|
||||
#[inline]
|
||||
fn eq(&self,other:&Self)->bool{
|
||||
self.bits.eq(&other.bits)
|
||||
}
|
||||
}
|
||||
impl<const N:usize,const F:usize,T> PartialEq<T> for Fixed<N,F>
|
||||
where
|
||||
T:Copy,
|
||||
BInt::<N>:From<T>,
|
||||
{
|
||||
#[inline]
|
||||
fn eq(&self,&other:&T)->bool{
|
||||
self.bits.eq(&other.into())
|
||||
}
|
||||
}
|
||||
impl<const N:usize,const F:usize> Eq for Fixed<N,F>{}
|
||||
|
||||
impl<const N:usize,const F:usize> PartialOrd for Fixed<N,F>{
|
||||
#[inline]
|
||||
fn partial_cmp(&self,other:&Self)->Option<std::cmp::Ordering>{
|
||||
self.bits.partial_cmp(&other.bits)
|
||||
}
|
||||
}
|
||||
impl<const N:usize,const F:usize,T> PartialOrd<T> for Fixed<N,F>
|
||||
where
|
||||
T:Copy,
|
||||
BInt::<N>:From<T>,
|
||||
{
|
||||
#[inline]
|
||||
fn partial_cmp(&self,&other:&T)->Option<std::cmp::Ordering>{
|
||||
self.bits.partial_cmp(&other.into())
|
||||
}
|
||||
}
|
||||
impl<const N:usize,const F:usize> Ord for Fixed<N,F>{
|
||||
#[inline]
|
||||
fn cmp(&self,other:&Self)->std::cmp::Ordering{
|
||||
self.bits.cmp(&other.bits)
|
||||
}
|
||||
@@ -102,13 +67,11 @@ impl<const N:usize,const F:usize> Ord for Fixed<N,F>{
|
||||
|
||||
impl<const N:usize,const F:usize> std::ops::Neg for Fixed<N,F>{
|
||||
type Output=Self;
|
||||
#[inline]
|
||||
fn neg(self)->Self{
|
||||
Self::from_bits(self.bits.neg())
|
||||
}
|
||||
}
|
||||
impl<const N:usize,const F:usize> std::iter::Sum for Fixed<N,F>{
|
||||
#[inline]
|
||||
fn sum<I:Iterator<Item=Self>>(iter:I)->Self{
|
||||
let mut sum=Self::ZERO;
|
||||
for elem in iter{
|
||||
@@ -118,40 +81,6 @@ impl<const N:usize,const F:usize> std::iter::Sum for Fixed<N,F>{
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_into_float {
|
||||
( $output: ty ) => {
|
||||
impl<const N:usize,const F:usize> Into<$output> for Fixed<N,F>{
|
||||
#[inline]
|
||||
fn into(self)->$output{
|
||||
let mut total=0.0;
|
||||
let bits=self.bits.to_bits();
|
||||
let digits=bits.digits();
|
||||
for (i,digit) in digits[0..N-1].iter().enumerate(){
|
||||
// (i*64-F) as i32 will interpret the highest order bit as a sign bit but whatever
|
||||
total+=(*digit as $output)*(2.0 as $output).powi((i*64-F) as i32);
|
||||
}
|
||||
//most significant digit holds the sign bit
|
||||
//assume we are using a number with at least 1 digit...
|
||||
total+=((*digits.last().unwrap() as i64).abs() as $output)*(2.0 as $output).powi(((N-1)*64-F) as i32);
|
||||
if self.bits.is_negative(){
|
||||
total=-total;
|
||||
}
|
||||
total
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl_into_float!(f32);
|
||||
impl_into_float!(f64);
|
||||
|
||||
impl<const N:usize,const F:usize> core::fmt::Display for Fixed<N,F>{
|
||||
#[inline]
|
||||
fn fmt(&self,f:&mut core::fmt::Formatter)->Result<(),core::fmt::Error>{
|
||||
let float:f32=(*self).into();
|
||||
core::write!(f,"{:.3}",float)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_additive_operator {
|
||||
( $struct: ident, $trait: ident, $method: ident, $output: ty ) => {
|
||||
impl<const N:usize,const F:usize> $struct<N,F>{
|
||||
@@ -162,7 +91,6 @@ macro_rules! impl_additive_operator {
|
||||
}
|
||||
impl<const N:usize,const F:usize> core::ops::$trait for $struct<N,F>{
|
||||
type Output = $output;
|
||||
#[inline]
|
||||
fn $method(self, other: Self) -> Self::Output {
|
||||
self.$method(other)
|
||||
}
|
||||
@@ -172,7 +100,6 @@ macro_rules! impl_additive_operator {
|
||||
BInt::<N>:From<U>,
|
||||
{
|
||||
type Output = $output;
|
||||
#[inline]
|
||||
fn $method(self, other: U) -> Self::Output {
|
||||
Self::from_bits(self.bits.$method(BInt::<N>::from(other).shl(F as u32)))
|
||||
}
|
||||
@@ -182,7 +109,6 @@ macro_rules! impl_additive_operator {
|
||||
macro_rules! impl_additive_assign_operator {
|
||||
( $struct: ident, $trait: ident, $method: ident ) => {
|
||||
impl<const N:usize,const F:usize> core::ops::$trait for $struct<N,F>{
|
||||
#[inline]
|
||||
fn $method(&mut self, other: Self) {
|
||||
self.bits.$method(other.bits);
|
||||
}
|
||||
@@ -191,7 +117,6 @@ macro_rules! impl_additive_assign_operator {
|
||||
where
|
||||
BInt::<N>:From<U>,
|
||||
{
|
||||
#[inline]
|
||||
fn $method(&mut self, other: U) {
|
||||
self.bits.$method(BInt::<N>::from(other).shl(F as u32));
|
||||
}
|
||||
@@ -223,7 +148,6 @@ macro_rules! impl_multiplicative_operator_not_const_generic {
|
||||
( ($struct: ident, $trait: ident, $method: ident, $output: ty ), $width:expr ) => {
|
||||
impl<const F:usize> core::ops::$trait for $struct<$width,F>{
|
||||
type Output = $output;
|
||||
#[inline]
|
||||
fn $method(self, other: Self) -> Self::Output {
|
||||
paste::item!{
|
||||
self.[<fixed_ $method>](other)
|
||||
@@ -235,7 +159,6 @@ macro_rules! impl_multiplicative_operator_not_const_generic {
|
||||
macro_rules! impl_multiplicative_assign_operator_not_const_generic {
|
||||
( ($struct: ident, $trait: ident, $method: ident, $non_assign_method: ident ), $width:expr ) => {
|
||||
impl<const F:usize> core::ops::$trait for $struct<$width,F>{
|
||||
#[inline]
|
||||
fn $method(&mut self, other: Self) {
|
||||
paste::item!{
|
||||
*self=self.[<fixed_ $non_assign_method>](other);
|
||||
@@ -274,7 +197,7 @@ macro_rules! impl_divide_operator_not_const_generic {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(all(not(feature="wide-mul"),not(feature="deferred-division")))]
|
||||
#[cfg(all(not(feature="wide-mul"),not(feature="ratio")))]
|
||||
impl_multiplicative_operator_not_const_generic!(($struct, $trait, $method, $output ), $width);
|
||||
};
|
||||
}
|
||||
@@ -286,7 +209,7 @@ macro_rules! impl_multiplicative_operator {
|
||||
BInt::<N>:From<U>+core::ops::$trait,
|
||||
{
|
||||
type Output = $output;
|
||||
#[inline]
|
||||
|
||||
fn $method(self, other: U) -> Self::Output {
|
||||
Self::from_bits(self.bits.$method(BInt::<N>::from(other)))
|
||||
}
|
||||
@@ -299,7 +222,6 @@ macro_rules! impl_multiplicative_assign_operator {
|
||||
where
|
||||
BInt::<N>:From<U>+core::ops::$trait,
|
||||
{
|
||||
#[inline]
|
||||
fn $method(&mut self, other: U) {
|
||||
self.bits.$method(BInt::<N>::from(other));
|
||||
}
|
||||
@@ -333,20 +255,21 @@ impl_multiplicative_assign_operator!( Fixed, MulAssign, mul_assign );
|
||||
impl_multiplicative_operator!( Fixed, Mul, mul, Self );
|
||||
impl_multiplicative_assign_operator!( Fixed, DivAssign, div_assign );
|
||||
impl_multiplicative_operator!( Fixed, Div, div, Self );
|
||||
#[cfg(feature="deferred-division")]
|
||||
#[cfg(feature="ratio")]
|
||||
impl<const LHS_N:usize,const LHS_F:usize,const RHS_N:usize,const RHS_F:usize> core::ops::Div<Fixed<RHS_N,RHS_F>> for Fixed<LHS_N,LHS_F>{
|
||||
type Output=ratio_ops::ratio::Ratio<Fixed<LHS_N,LHS_F>,Fixed<RHS_N,RHS_F>>;
|
||||
#[inline]
|
||||
type Output=crate::ratio::Ratio<Fixed<LHS_N,LHS_F>,Fixed<RHS_N,RHS_F>>;
|
||||
fn div(self, other: Fixed<RHS_N,RHS_F>)->Self::Output{
|
||||
ratio_ops::ratio::Ratio::new(self,other)
|
||||
crate::ratio::Ratio::new(self,other)
|
||||
}
|
||||
}
|
||||
|
||||
// wide operators. The result width is the sum of the input widths, i.e. none of the multiplication
|
||||
|
||||
macro_rules! impl_shift_operator {
|
||||
( $struct: ident, $trait: ident, $method: ident, $output: ty ) => {
|
||||
impl<const N:usize,const F:usize> core::ops::$trait<u32> for $struct<N,F>{
|
||||
type Output = $output;
|
||||
#[inline]
|
||||
|
||||
fn $method(self, other: u32) -> Self::Output {
|
||||
Self::from_bits(self.bits.$method(other))
|
||||
}
|
||||
@@ -356,7 +279,6 @@ macro_rules! impl_shift_operator {
|
||||
macro_rules! impl_shift_assign_operator {
|
||||
( $struct: ident, $trait: ident, $method: ident ) => {
|
||||
impl<const N:usize,const F:usize> core::ops::$trait<u32> for $struct<N,F>{
|
||||
#[inline]
|
||||
fn $method(&mut self, other: u32) {
|
||||
self.bits.$method(other);
|
||||
}
|
||||
@@ -368,23 +290,19 @@ impl_shift_operator!( Fixed, Shl, shl, Self );
|
||||
impl_shift_assign_operator!( Fixed, ShrAssign, shr_assign );
|
||||
impl_shift_operator!( Fixed, Shr, shr, Self );
|
||||
|
||||
// wide operators. The result width is the sum of the input widths, i.e. none of the multiplication
|
||||
|
||||
macro_rules! impl_wide_operators{
|
||||
($lhs:expr,$rhs:expr)=>{
|
||||
impl core::ops::Mul<Fixed<$rhs,{$rhs*32}>> for Fixed<$lhs,{$lhs*32}>{
|
||||
type Output=Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>;
|
||||
#[inline]
|
||||
fn mul(self, other: Fixed<$rhs,{$rhs*32}>)->Self::Output{
|
||||
paste::item!{
|
||||
self.[<wide_mul_ $lhs _ $rhs>](other)
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature="deferred-division"))]
|
||||
#[cfg(not(feature="ratio"))]
|
||||
impl core::ops::Div<Fixed<$rhs,{$rhs*32}>> for Fixed<$lhs,{$lhs*32}>{
|
||||
type Output=Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>;
|
||||
#[inline]
|
||||
fn div(self, other: Fixed<$rhs,{$rhs*32}>)->Self::Output{
|
||||
paste::item!{
|
||||
self.[<wide_div_ $lhs _ $rhs>](other)
|
||||
@@ -405,7 +323,6 @@ macro_rules! impl_wide_not_const_generic{
|
||||
impl Fixed<$lhs,{$lhs*32}>
|
||||
{
|
||||
paste::item!{
|
||||
#[inline]
|
||||
pub fn [<wide_mul_ $lhs _ $rhs>](self,rhs:Fixed<$rhs,{$rhs*32}>)->Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>{
|
||||
let lhs=self.bits.as_::<BInt<{$lhs+$rhs}>>();
|
||||
let rhs=rhs.bits.as_::<BInt<{$lhs+$rhs}>>();
|
||||
@@ -414,7 +331,6 @@ macro_rules! impl_wide_not_const_generic{
|
||||
/// This operation cannot represent the fraction exactly,
|
||||
/// but it shapes the output to have precision for the
|
||||
/// largest and smallest possible fractions.
|
||||
#[inline]
|
||||
pub fn [<wide_div_ $lhs _ $rhs>](self,rhs:Fixed<$rhs,{$rhs*32}>)->Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>{
|
||||
// (lhs/2^LHS_FRAC)/(rhs/2^RHS_FRAC)
|
||||
let lhs=self.bits.as_::<BInt<{$lhs+$rhs}>>().shl($rhs*64);
|
||||
@@ -448,7 +364,6 @@ macro_repeated!(
|
||||
(1,15)
|
||||
);
|
||||
impl<const SRC:usize,const F:usize> Fixed<SRC,F>{
|
||||
#[inline]
|
||||
pub fn resize_into<const DST:usize>(self)->Fixed<DST,F>{
|
||||
Fixed::from_bits(self.bits.as_::<BInt<DST>>())
|
||||
}
|
||||
@@ -457,14 +372,12 @@ impl<const SRC:usize,const F:usize> Fixed<SRC,F>{
|
||||
macro_rules! impl_not_const_generic{
|
||||
($n:expr)=>{
|
||||
impl Fixed<{$n*2},{$n*2*32}>{
|
||||
#[inline]
|
||||
pub fn halve_precision(self)->Fixed<$n,{$n*32}>{
|
||||
Fixed::from_bits(bnum::cast::As::as_(self.bits.shr($n*32)))
|
||||
}
|
||||
}
|
||||
impl Fixed<$n,{$n*32}>{
|
||||
paste::item!{
|
||||
#[inline]
|
||||
pub fn sqrt_unchecked(self)->Self{
|
||||
//1<<max_shift must be the minimum power of two which when squared is greater than self
|
||||
//calculating max_shift:
|
||||
@@ -477,19 +390,17 @@ macro_rules! impl_not_const_generic{
|
||||
let mut result=Self::ZERO;
|
||||
|
||||
//multiply by one to make the types match (hack)
|
||||
//TODO: use resize method
|
||||
let wide_self:<Self as core::ops::Mul>::Output=self*Self::ONE;
|
||||
let wide_self=self.[<wide_mul_ $n _ $n>](Self::ONE);
|
||||
//descend down the bits and check if flipping each bit would push the square over the input value
|
||||
for shift in (0..=max_shift).rev(){
|
||||
let new_result=result|Self::from_bits(BInt::from_bits(bnum::BUint::power_of_two(shift)));
|
||||
if new_result*new_result<=wide_self{
|
||||
if new_result.[<wide_mul_ $n _ $n>](new_result)<=wide_self{
|
||||
result=new_result;
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn sqrt(self)->Self{
|
||||
if self<Self::ZERO{
|
||||
panic!("Square root less than zero")
|
||||
@@ -497,7 +408,6 @@ macro_rules! impl_not_const_generic{
|
||||
self.sqrt_unchecked()
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn sqrt_checked(self)->Option<Self>{
|
||||
if self<Self::ZERO{
|
||||
None
|
||||
|
||||
@@ -3,6 +3,8 @@ pub mod types;
|
||||
|
||||
#[cfg(feature="zeroes")]
|
||||
pub mod zeroes;
|
||||
#[cfg(feature="ratio")]
|
||||
pub mod ratio;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
10
fixed_wide/src/ratio.rs
Normal file
10
fixed_wide/src/ratio.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
#[derive(Clone,Copy,Debug,Hash)]
|
||||
pub struct Ratio<Num,Den>{
|
||||
pub(crate)num:Num,
|
||||
pub(crate)den:Den,
|
||||
}
|
||||
impl<Num,Den> Ratio<Num,Den>{
|
||||
pub const fn new(num:Num,den:Den)->Self{
|
||||
Self{num,den}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::fixed::Fixed;
|
||||
use crate::ratio::Ratio;
|
||||
|
||||
use arrayvec::ArrayVec;
|
||||
use std::cmp::Ordering;
|
||||
@@ -6,38 +7,36 @@ macro_rules! impl_zeroes{
|
||||
($n:expr)=>{
|
||||
impl Fixed<$n,{$n*32}>{
|
||||
#[inline]
|
||||
pub fn zeroes2(a0:Self,a1:Self,a2:Self)->ArrayVec<<Self as core::ops::Div>::Output,2>{
|
||||
pub fn zeroes2(a0:Self,a1:Self,a2:Self)->ArrayVec<Ratio<Self,Self>,2>{
|
||||
let a2pos=match a2.cmp(&Self::ZERO){
|
||||
Ordering::Greater=>true,
|
||||
Ordering::Equal=>return ArrayVec::from_iter(Self::zeroes1(a0,a1).into_iter()),
|
||||
Ordering::Less=>true,
|
||||
};
|
||||
paste::item!{
|
||||
let radicand=a1*a1-a2*a0*4;
|
||||
let radicand=a1.[<wide_mul_ $n _ $n>](a1)-a2.[<wide_mul_ $n _ $n>](a0)*4;
|
||||
}
|
||||
match radicand.cmp(&<Self as core::ops::Mul>::Output::ZERO){
|
||||
match radicand.cmp(&Fixed::<{$n*2},{$n*2*32}>::ZERO){
|
||||
Ordering::Greater=>{
|
||||
//TODO: use resize method
|
||||
let planar_radicand:Self=radicand.sqrt().halve_precision();
|
||||
let planar_radicand=radicand.sqrt().halve_precision();
|
||||
//sort roots ascending and avoid taking the difference of large numbers
|
||||
let zeroes=match (a2pos,Self::ZERO<a1){
|
||||
(true, true )=>[(-a1-planar_radicand)/(a2*2),(a0*2)/(-a1-planar_radicand)],
|
||||
(true, false)=>[(a0*2)/(-a1+planar_radicand),(-a1+planar_radicand)/(a2*2)],
|
||||
(false,true )=>[(a0*2)/(-a1-planar_radicand),(-a1-planar_radicand)/(a2*2)],
|
||||
(false,false)=>[(-a1+planar_radicand)/(a2*2),(a0*2)/(-a1+planar_radicand)],
|
||||
};
|
||||
ArrayVec::from_iter(zeroes)
|
||||
match (a2pos,Self::ZERO<a1){
|
||||
(true, true )=>[Ratio::new(-a1-planar_radicand,a2*2),Ratio::new(a0*2,-a1-planar_radicand)].into(),
|
||||
(true, false)=>[Ratio::new(a0*2,-a1+planar_radicand),Ratio::new(-a1+planar_radicand,a2*2)].into(),
|
||||
(false,true )=>[Ratio::new(a0*2,-a1-planar_radicand),Ratio::new(-a1-planar_radicand,a2*2)].into(),
|
||||
(false,false)=>[Ratio::new(-a1+planar_radicand,a2*2),Ratio::new(a0*2,-a1+planar_radicand)].into(),
|
||||
}
|
||||
},
|
||||
Ordering::Equal=>ArrayVec::from_iter([(a1)/(a2*-2)]),
|
||||
Ordering::Equal=>ArrayVec::from_iter([Ratio::new(a1,a2*-2)]),
|
||||
Ordering::Less=>ArrayVec::new_const(),
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn zeroes1(a0:Self,a1:Self)->ArrayVec<<Self as core::ops::Div>::Output,1>{
|
||||
pub fn zeroes1(a0:Self,a1:Self)->ArrayVec<Ratio<Self,Self>,1>{
|
||||
if a1==Self::ZERO{
|
||||
ArrayVec::new_const()
|
||||
}else{
|
||||
ArrayVec::from_iter([(-a0)/(a1)])
|
||||
ArrayVec::from_iter([Ratio::new(-a0,a1)])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||
|
||||
[[package]]
|
||||
name = "bnum"
|
||||
version = "0.11.0"
|
||||
@@ -12,16 +18,17 @@ checksum = "3e31ea183f6ee62ac8b8a8cf7feddd766317adfb13ff469de57ce033efd6a790"
|
||||
name = "fixed_wide"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bnum",
|
||||
"paste",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linear_ops"
|
||||
name = "fixed_wide_vectors"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"fixed_wide",
|
||||
"ratio_ops",
|
||||
"paste",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -29,7 +36,3 @@ name = "paste"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "ratio_ops"
|
||||
version = "0.1.0"
|
||||
13
fixed_wide_vectors/Cargo.toml
Normal file
13
fixed_wide_vectors/Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "fixed_wide_vectors"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
default=["fixed_wide","named-fields"]
|
||||
named-fields=[]
|
||||
fixed_wide=["dep:fixed_wide","dep:paste"]
|
||||
|
||||
[dependencies]
|
||||
fixed_wide = { version = "0.1.0", path = "../fixed_wide", optional = true }
|
||||
paste = { version = "1.0.15", optional = true }
|
||||
212
fixed_wide_vectors/src/macros/fixed_wide.rs
Normal file
212
fixed_wide_vectors/src/macros/fixed_wide.rs
Normal file
@@ -0,0 +1,212 @@
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_wide_vector_operations_2arg_not_const_generic {
|
||||
(
|
||||
(),
|
||||
($lhs:expr, $rhs:expr)
|
||||
) => {
|
||||
impl<const N:usize> Vector<N,fixed_wide::fixed::Fixed<{$lhs},{$lhs*32}>>{
|
||||
paste::item!{
|
||||
#[inline]
|
||||
pub fn [<wide_mul_ $lhs _ $rhs>](self,rhs:Vector<N,fixed_wide::fixed::Fixed<{$rhs},{$rhs*32}>>)->Vector<N,fixed_wide::fixed::Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>>{
|
||||
self.map_zip(rhs,|(a,b)|a.[<wide_mul_ $lhs _ $rhs>](b))
|
||||
}
|
||||
#[inline]
|
||||
pub fn [<wide_dot_ $lhs _ $rhs>](self,rhs:Vector<N,fixed_wide::fixed::Fixed<{$rhs},{$rhs*32}>>)->fixed_wide::fixed::Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>{
|
||||
self.array.into_iter().zip(rhs.array).map(|(a,b)|a.[<wide_mul_ $lhs _ $rhs>](b)).sum()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_wide_vector_operations_1arg_not_const_generic {
|
||||
(
|
||||
(),
|
||||
$n:expr
|
||||
) => {
|
||||
impl<const N:usize> Vector<N,fixed_wide::fixed::Fixed<{$n},{$n*32}>>{
|
||||
paste::item!{
|
||||
#[inline]
|
||||
pub fn wide_length_squared(&self)->fixed_wide::fixed::Fixed<{$n*2},{$n*2*32}>{
|
||||
self.array.into_iter().map(|t|t.[<wide_mul_ $n _ $n>](t)).sum()
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! do_macro_8x8{
|
||||
(
|
||||
$macro:ident,
|
||||
$any:tt
|
||||
)=>{
|
||||
$crate::macro_repeated!($macro, $any,
|
||||
(1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),
|
||||
(1,2),(2,2),(3,2),(4,2),(5,2),(6,2),(7,2),(8,2),
|
||||
(1,3),(2,3),(3,3),(4,3),(5,3),(6,3),(7,3),(8,3),
|
||||
(1,4),(2,4),(3,4),(4,4),(5,4),(6,4),(7,4),(8,4),
|
||||
(1,5),(2,5),(3,5),(4,5),(5,5),(6,5),(7,5),(8,5),
|
||||
(1,6),(2,6),(3,6),(4,6),(5,6),(6,6),(7,6),(8,6),
|
||||
(1,7),(2,7),(3,7),(4,7),(5,7),(6,7),(7,7),(8,7),
|
||||
(1,8),(2,8),(3,8),(4,8),(5,8),(6,8),(7,8),(8,8)
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! do_macro_8{
|
||||
(
|
||||
$macro:ident,
|
||||
$any:tt
|
||||
)=>{
|
||||
$crate::macro_repeated!($macro, $any, 1,2,3,4,5,6,7,8);
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_wide_vector_operations {
|
||||
() => {
|
||||
$crate::do_macro_8!(impl_wide_vector_operations_1arg_not_const_generic,());
|
||||
$crate::do_macro_8x8!(impl_wide_vector_operations_2arg_not_const_generic,());
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_vector_3_wide_cross {
|
||||
(
|
||||
(),
|
||||
($lhs:expr, $rhs:expr)
|
||||
)=>{
|
||||
impl Vector<3,fixed_wide::fixed::Fixed<{$lhs},{$lhs*32}>>{
|
||||
paste::item!{
|
||||
#[inline]
|
||||
pub fn [<wide_cross_ $lhs _ $rhs>](self,rhs:Vector<3,fixed_wide::fixed::Fixed<{$rhs},{$rhs*32}>>)->Vector<3,fixed_wide::fixed::Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>>{
|
||||
Vector::new([
|
||||
self.y.[<wide_mul_ $lhs _ $rhs>](rhs.z)-self.z.[<wide_mul_ $lhs _ $rhs>](rhs.y),
|
||||
self.z.[<wide_mul_ $lhs _ $rhs>](rhs.x)-self.x.[<wide_mul_ $lhs _ $rhs>](rhs.z),
|
||||
self.x.[<wide_mul_ $lhs _ $rhs>](rhs.y)-self.y.[<wide_mul_ $lhs _ $rhs>](rhs.x),
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_vector_wide_3 {
|
||||
()=>{
|
||||
$crate::do_macro_8x8!(impl_vector_3_wide_cross,());
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! do_macro_4_dumb{
|
||||
(
|
||||
$macro:ident,
|
||||
$any:tt
|
||||
)=>{
|
||||
$crate::macro_repeated!($macro, $any, (1,2),(2,4),(3,6),(4,8));
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_matrix_wide_dot {
|
||||
(
|
||||
(),
|
||||
($lhs: expr, $rhs: expr)
|
||||
) => {
|
||||
impl<const X:usize,const Y:usize> Matrix<X,Y,fixed_wide::fixed::Fixed<{$lhs},{$lhs*32}>>{
|
||||
paste::item!{
|
||||
#[inline]
|
||||
pub fn [<wide_dot_ $lhs _ $rhs>]<const Z:usize>(self,rhs:Matrix<Z,X,fixed_wide::fixed::Fixed<{$rhs},{$rhs*32}>>)->Matrix<Z,Y,fixed_wide::fixed::Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>>{
|
||||
let mut array_of_iterators=rhs.array.map(|axis|axis.into_iter().cycle());
|
||||
Matrix::new(
|
||||
self.array.map(|axis|
|
||||
core::array::from_fn(|_|
|
||||
// axis dot product with transposed rhs array
|
||||
axis.iter().zip(
|
||||
array_of_iterators.iter_mut()
|
||||
).map(|(&lhs_value,rhs_iter)|
|
||||
lhs_value.[<wide_mul_ $lhs _ $rhs>](rhs_iter.next().unwrap())
|
||||
).sum()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_matrix_wide_dot_8x8 {
|
||||
() => {
|
||||
$crate::do_macro_8x8!(impl_matrix_wide_dot,());
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_matrix_wide_3x3_det_not_const_generic {
|
||||
(
|
||||
$n: expr,
|
||||
$_2n: expr
|
||||
)=>{
|
||||
impl Matrix<3,3,fixed_wide::fixed::Fixed<$n,{$n*32}>>{
|
||||
paste::item!{
|
||||
pub fn [<wide_det_3x3_ $n>](self)->fixed_wide::fixed::Fixed<{$n*3},{$n*3*32}>{
|
||||
//[<wide_dot_ $n _ $n*2>] will not compile, so the doubles are hardcoded above
|
||||
self.x_axis.[<wide_dot_ $n _ $_2n>](self.y_axis.[<wide_cross_ $n _ $n>](self.z_axis))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_matrix_wide_3x3_det_not_const_generic_shim {
|
||||
(
|
||||
(),($n: expr,$_2n: expr)
|
||||
)=>{
|
||||
$crate::impl_matrix_wide_3x3_det_not_const_generic!($n,$_2n);
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_matrix_wide_3x3_adjugate_not_const_generic {
|
||||
(
|
||||
(),
|
||||
$n: expr
|
||||
)=>{
|
||||
impl Matrix<3,3,fixed_wide::fixed::Fixed<$n,{$n*32}>>{
|
||||
paste::item!{
|
||||
pub fn [<wide_adjugate_3x3_ $n>](self)->Matrix<3,3,fixed_wide::fixed::Fixed<{$n*2},{$n*2*32}>>{
|
||||
Matrix::new([
|
||||
[self.y_axis.y.[<wide_mul_ $n _ $n>](self.z_axis.z)-self.y_axis.z.[<wide_mul_ $n _ $n>](self.z_axis.y),self.x_axis.z.[<wide_mul_ $n _ $n>](self.z_axis.y)-self.x_axis.y.[<wide_mul_ $n _ $n>](self.z_axis.z),self.x_axis.y.[<wide_mul_ $n _ $n>](self.y_axis.z)-self.x_axis.z.[<wide_mul_ $n _ $n>](self.y_axis.y)],
|
||||
[self.y_axis.z.[<wide_mul_ $n _ $n>](self.z_axis.x)-self.y_axis.x.[<wide_mul_ $n _ $n>](self.z_axis.z),self.x_axis.x.[<wide_mul_ $n _ $n>](self.z_axis.z)-self.x_axis.z.[<wide_mul_ $n _ $n>](self.z_axis.x),self.x_axis.z.[<wide_mul_ $n _ $n>](self.y_axis.x)-self.x_axis.x.[<wide_mul_ $n _ $n>](self.y_axis.z)],
|
||||
[self.y_axis.x.[<wide_mul_ $n _ $n>](self.z_axis.y)-self.y_axis.y.[<wide_mul_ $n _ $n>](self.z_axis.x),self.x_axis.y.[<wide_mul_ $n _ $n>](self.z_axis.x)-self.x_axis.x.[<wide_mul_ $n _ $n>](self.z_axis.y),self.x_axis.x.[<wide_mul_ $n _ $n>](self.y_axis.y)-self.x_axis.y.[<wide_mul_ $n _ $n>](self.y_axis.x)],
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_matrix_wide_3x3 {
|
||||
()=>{
|
||||
$crate::do_macro_4_dumb!(impl_matrix_wide_3x3_det_not_const_generic_shim,());
|
||||
$crate::do_macro_8!(impl_matrix_wide_3x3_adjugate_not_const_generic,());
|
||||
}
|
||||
}
|
||||
@@ -54,102 +54,25 @@ macro_rules! impl_matrix {
|
||||
)
|
||||
)
|
||||
}
|
||||
#[inline]
|
||||
// MatY<VecX>.VecX = VecY
|
||||
pub fn transform_vector<U,V>(self,rhs:Vector<X,U>)->Vector<Y,V>
|
||||
where
|
||||
T:core::ops::Mul<U,Output=V>,
|
||||
V:core::iter::Sum,
|
||||
U:Copy,
|
||||
{
|
||||
Vector::new(
|
||||
self.array.map(|axis|
|
||||
Vector::new(axis).dot(rhs)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
impl<const X:usize,const Y:usize,T> Matrix<X,Y,T>
|
||||
where
|
||||
T:Copy
|
||||
{
|
||||
#[inline(always)]
|
||||
pub const fn from_value(value:T)->Self{
|
||||
Self::new([[value;X];Y])
|
||||
}
|
||||
}
|
||||
|
||||
impl<const X:usize,const Y:usize,T:Default> Default for Matrix<X,Y,T>{
|
||||
#[inline]
|
||||
fn default()->Self{
|
||||
Self::new(
|
||||
core::array::from_fn(|_|core::array::from_fn(|_|Default::default()))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const X:usize,const Y:usize,T:core::fmt::Display> core::fmt::Display for Matrix<X,Y,T>{
|
||||
#[inline]
|
||||
fn fmt(&self,f:&mut core::fmt::Formatter)->Result<(),core::fmt::Error>{
|
||||
for row in &self.array[0..Y]{
|
||||
core::write!(f,"\n")?;
|
||||
for elem in &row[0..X-1]{
|
||||
core::write!(f,"{}, ",elem)?;
|
||||
}
|
||||
// assume we will be using matrices of size 1x1 or greater
|
||||
core::write!(f,"{}",row.last().unwrap())?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<const X:usize,const Y:usize,const Z:usize,T,U,V> core::ops::Mul<Matrix<Z,X,U>> for Matrix<X,Y,T>
|
||||
where
|
||||
T:core::ops::Mul<U,Output=V>+Copy,
|
||||
V:core::iter::Sum,
|
||||
U:Copy,
|
||||
{
|
||||
type Output=Matrix<Z,Y,V>;
|
||||
#[inline]
|
||||
fn mul(self,rhs:Matrix<Z,X,U>)->Self::Output{
|
||||
self.dot(rhs)
|
||||
}
|
||||
}
|
||||
impl<const X:usize,const Y:usize,T,U,V> core::ops::Mul<Vector<X,U>> for Matrix<X,Y,T>
|
||||
where
|
||||
T:core::ops::Mul<U,Output=V>,
|
||||
V:core::iter::Sum,
|
||||
U:Copy,
|
||||
{
|
||||
type Output=Vector<Y,V>;
|
||||
#[inline]
|
||||
fn mul(self,rhs:Vector<X,U>)->Self::Output{
|
||||
self.transform_vector(rhs)
|
||||
}
|
||||
}
|
||||
#[cfg(feature="deferred-division")]
|
||||
$crate::impl_matrix_deferred_division!();
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_matrix_deferred_division {
|
||||
() => {
|
||||
impl<const X:usize,const Y:usize,T:ratio_ops::ratio::Divide<U,Output=V>,U:Copy,V> ratio_ops::ratio::Divide<U> for Matrix<X,Y,T>{
|
||||
type Output=Matrix<X,Y,V>;
|
||||
#[inline]
|
||||
fn divide(self,rhs:U)->Self::Output{
|
||||
self.map(|t|t.divide(rhs))
|
||||
}
|
||||
}
|
||||
impl<const X:usize,const Y:usize,T,U> core::ops::Div<U> for Matrix<X,Y,T>{
|
||||
type Output=ratio_ops::ratio::Ratio<Matrix<X,Y,T>,U>;
|
||||
#[inline]
|
||||
fn div(self,rhs:U)->Self::Output{
|
||||
ratio_ops::ratio::Ratio::new(self,rhs)
|
||||
}
|
||||
}
|
||||
#[cfg(feature="fixed_wide")]
|
||||
$crate::impl_matrix_wide_dot_8x8!();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,13 +111,11 @@ macro_rules! impl_matrix_named_fields_shape {
|
||||
) => {
|
||||
impl<T> core::ops::Deref for Matrix<$size_outer,$size_inner,T>{
|
||||
type Target=$struct_outer<Vector<$size_inner,T>>;
|
||||
#[inline]
|
||||
fn deref(&self)->&Self::Target{
|
||||
unsafe{core::mem::transmute(&self.array)}
|
||||
}
|
||||
}
|
||||
impl<T> core::ops::DerefMut for Matrix<$size_outer,$size_inner,T>{
|
||||
#[inline]
|
||||
fn deref_mut(&mut self)->&mut Self::Target{
|
||||
unsafe{core::mem::transmute(&mut self.array)}
|
||||
}
|
||||
@@ -228,31 +149,7 @@ macro_rules! impl_matrix_named_fields {
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_matrix_3x3 {
|
||||
()=>{
|
||||
impl<T,T2,T3> Matrix<3,3,T>
|
||||
where
|
||||
//cross
|
||||
T:core::ops::Mul<T,Output=T2>+Copy,
|
||||
T2:core::ops::Sub,
|
||||
//dot
|
||||
T:core::ops::Mul<<T2 as core::ops::Sub>::Output,Output=T3>,
|
||||
T3:core::iter::Sum,
|
||||
{
|
||||
pub fn det(self)->T3{
|
||||
self.x_axis.dot(self.y_axis.cross(self.z_axis))
|
||||
}
|
||||
}
|
||||
impl<T,T2> Matrix<3,3,T>
|
||||
where
|
||||
T:core::ops::Mul<T,Output=T2>+Copy,
|
||||
T2:core::ops::Sub,
|
||||
{
|
||||
pub fn adjugate(self)->Matrix<3,3,<T2 as core::ops::Sub>::Output>{
|
||||
Matrix::new([
|
||||
[self.y_axis.y*self.z_axis.z-self.y_axis.z*self.z_axis.y,self.x_axis.z*self.z_axis.y-self.x_axis.y*self.z_axis.z,self.x_axis.y*self.y_axis.z-self.x_axis.z*self.y_axis.y],
|
||||
[self.y_axis.z*self.z_axis.x-self.y_axis.x*self.z_axis.z,self.x_axis.x*self.z_axis.z-self.x_axis.z*self.z_axis.x,self.x_axis.z*self.y_axis.x-self.x_axis.x*self.y_axis.z],
|
||||
[self.y_axis.x*self.z_axis.y-self.y_axis.y*self.z_axis.x,self.x_axis.y*self.z_axis.x-self.x_axis.x*self.z_axis.y,self.x_axis.x*self.y_axis.y-self.x_axis.y*self.y_axis.x],
|
||||
])
|
||||
}
|
||||
}
|
||||
#[cfg(feature="fixed_wide")]
|
||||
$crate::impl_matrix_wide_3x3!();
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
#[cfg(feature="fixed_wide")]
|
||||
pub mod fixed_wide;
|
||||
|
||||
pub mod common;
|
||||
pub mod vector;
|
||||
pub mod matrix;
|
||||
@@ -39,7 +39,6 @@ macro_rules! impl_vector {
|
||||
}
|
||||
|
||||
impl<const N:usize,T:Default> Default for Vector<N,T>{
|
||||
#[inline]
|
||||
fn default()->Self{
|
||||
Self::new(
|
||||
core::array::from_fn(|_|Default::default())
|
||||
@@ -47,17 +46,6 @@ macro_rules! impl_vector {
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N:usize,T:core::fmt::Display> core::fmt::Display for Vector<N,T>{
|
||||
#[inline]
|
||||
fn fmt(&self,f:&mut core::fmt::Formatter)->Result<(),core::fmt::Error>{
|
||||
for elem in &self.array[0..N-1]{
|
||||
core::write!(f,"{}, ",elem)?;
|
||||
}
|
||||
// assume we will be using vectors of length 1 or greater
|
||||
core::write!(f,"{}",self.array.last().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N:usize,T:Ord> Vector<N,T>{
|
||||
#[inline]
|
||||
pub fn min(self,rhs:Self)->Self{
|
||||
@@ -102,7 +90,6 @@ macro_rules! impl_vector {
|
||||
|
||||
impl<const N:usize,T:core::ops::Neg<Output=V>,V> core::ops::Neg for Vector<N,T>{
|
||||
type Output=Vector<N,V>;
|
||||
#[inline]
|
||||
fn neg(self)->Self::Output{
|
||||
Vector::new(
|
||||
self.array.map(|t|-t)
|
||||
@@ -110,47 +97,18 @@ macro_rules! impl_vector {
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N:usize,T> Vector<N,T>
|
||||
{
|
||||
#[inline]
|
||||
pub fn dot<U,V>(self,rhs:Vector<N,U>)->V
|
||||
where
|
||||
T:core::ops::Mul<U,Output=V>,
|
||||
V:core::iter::Sum,
|
||||
{
|
||||
self.array.into_iter().zip(rhs.array).map(|(a,b)|a*b).sum()
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N:usize,T,V> Vector<N,T>
|
||||
where
|
||||
T:core::ops::Mul<Output=V>+Copy,
|
||||
V:core::iter::Sum,
|
||||
{
|
||||
#[inline]
|
||||
pub fn length_squared(self)->V{
|
||||
self.array.into_iter().map(|t|t*t).sum()
|
||||
}
|
||||
}
|
||||
|
||||
// Impl arithmetic operators
|
||||
$crate::impl_vector_assign_operator!(AddAssign, add_assign );
|
||||
$crate::impl_vector_operator!(Add, add );
|
||||
$crate::impl_vector_assign_operator!(SubAssign, sub_assign );
|
||||
$crate::impl_vector_operator!(Sub, sub );
|
||||
$crate::impl_vector_assign_operator!(MulAssign, mul_assign );
|
||||
$crate::impl_vector_operator!(Mul, mul );
|
||||
$crate::impl_vector_assign_operator!(DivAssign, div_assign );
|
||||
$crate::impl_vector_operator!(Div, div );
|
||||
$crate::impl_vector_assign_operator!(RemAssign, rem_assign );
|
||||
$crate::impl_vector_operator!(Rem, rem );
|
||||
|
||||
// mul and div are special, usually you multiply by a scalar
|
||||
// and implementing both vec*vec and vec*scalar is conflicting implementations Q_Q
|
||||
$crate::impl_vector_assign_operator_scalar!(MulAssign, mul_assign );
|
||||
$crate::impl_vector_operator_scalar!(Mul, mul );
|
||||
$crate::impl_vector_assign_operator_scalar!(DivAssign, div_assign );
|
||||
#[cfg(not(feature="deferred-division"))]
|
||||
$crate::impl_vector_operator_scalar!(Div, div );
|
||||
#[cfg(feature="deferred-division")]
|
||||
$crate::impl_vector_deferred_division!();
|
||||
|
||||
// Impl bitwise operators
|
||||
$crate::impl_vector_assign_operator!(BitAndAssign, bitand_assign );
|
||||
$crate::impl_vector_operator!(BitAnd, bitand );
|
||||
@@ -159,44 +117,9 @@ macro_rules! impl_vector {
|
||||
$crate::impl_vector_assign_operator!(BitXorAssign, bitxor_assign );
|
||||
$crate::impl_vector_operator!(BitXor, bitxor );
|
||||
|
||||
// Impl shift operators
|
||||
$crate::impl_vector_shift_assign_operator!(ShlAssign, shl_assign);
|
||||
$crate::impl_vector_shift_operator!(Shl, shl);
|
||||
$crate::impl_vector_shift_assign_operator!(ShrAssign, shr_assign);
|
||||
$crate::impl_vector_shift_operator!(Shr, shr);
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_vector_deferred_division {
|
||||
() => {
|
||||
impl<const N:usize,T:ratio_ops::ratio::Divide<U,Output=V>,U:Copy,V> ratio_ops::ratio::Divide<U> for Vector<N,T>{
|
||||
type Output=Vector<N,V>;
|
||||
#[inline]
|
||||
fn divide(self,rhs:U)->Self::Output{
|
||||
self.map(|t|t.divide(rhs))
|
||||
}
|
||||
}
|
||||
impl<const N:usize,T,U> core::ops::Div<U> for Vector<N,T>{
|
||||
type Output=ratio_ops::ratio::Ratio<Vector<N,T>,U>;
|
||||
#[inline]
|
||||
fn div(self,rhs:U)->Self::Output{
|
||||
ratio_ops::ratio::Ratio::new(self,rhs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_vector_operator_scalar {
|
||||
($trait: ident, $method: ident ) => {
|
||||
impl<const N:usize,T:core::ops::$trait<U,Output=V>,U:Copy,V> core::ops::$trait<U> for Vector<N,T>{
|
||||
type Output=Vector<N,V>;
|
||||
#[inline]
|
||||
fn $method(self,rhs:U)->Self::Output{
|
||||
self.map(|t|t.$method(rhs))
|
||||
}
|
||||
}
|
||||
// Impl floating-point based methods
|
||||
#[cfg(feature="fixed_wide")]
|
||||
$crate::impl_wide_vector_operations!();
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
@@ -205,14 +128,12 @@ macro_rules! impl_vector_operator {
|
||||
($trait: ident, $method: ident ) => {
|
||||
impl<const N:usize,T:core::ops::$trait<U,Output=V>,U,V> core::ops::$trait<Vector<N,U>> for Vector<N,T>{
|
||||
type Output=Vector<N,V>;
|
||||
#[inline]
|
||||
fn $method(self,rhs:Vector<N,U>)->Self::Output{
|
||||
self.map_zip(rhs,|(a,b)|a.$method(b))
|
||||
}
|
||||
}
|
||||
impl<const N:usize,T:core::ops::$trait<i64,Output=T>> core::ops::$trait<i64> for Vector<N,T>{
|
||||
type Output=Self;
|
||||
#[inline]
|
||||
fn $method(self,rhs:i64)->Self::Output{
|
||||
self.map(|t|t.$method(rhs))
|
||||
}
|
||||
@@ -221,30 +142,15 @@ macro_rules! impl_vector_operator {
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_vector_assign_operator_scalar {
|
||||
($trait: ident, $method: ident ) => {
|
||||
impl<const N:usize,T:core::ops::$trait<U>,U:Copy> core::ops::$trait<U> for Vector<N,T>{
|
||||
#[inline]
|
||||
fn $method(&mut self,rhs:U){
|
||||
self.array.iter_mut()
|
||||
.for_each(|t|t.$method(rhs))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_vector_assign_operator {
|
||||
($trait: ident, $method: ident ) => {
|
||||
impl<const N:usize,T:core::ops::$trait<U>,U> core::ops::$trait<Vector<N,U>> for Vector<N,T>{
|
||||
#[inline]
|
||||
fn $method(&mut self,rhs:Vector<N,U>){
|
||||
self.array.iter_mut().zip(rhs.array)
|
||||
.for_each(|(a,b)|a.$method(b))
|
||||
}
|
||||
}
|
||||
impl<const N:usize,T:core::ops::$trait<i64>> core::ops::$trait<i64> for Vector<N,T>{
|
||||
#[inline]
|
||||
fn $method(&mut self,rhs:i64){
|
||||
self.array.iter_mut()
|
||||
.for_each(|t|t.$method(rhs))
|
||||
@@ -252,46 +158,6 @@ macro_rules! impl_vector_assign_operator {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_vector_shift_operator {
|
||||
($trait: ident, $method: ident ) => {
|
||||
impl<const N:usize,T:core::ops::$trait<U,Output=V>,U,V> core::ops::$trait<Vector<N,U>> for Vector<N,T>{
|
||||
type Output=Vector<N,V>;
|
||||
#[inline]
|
||||
fn $method(self,rhs:Vector<N,U>)->Self::Output{
|
||||
self.map_zip(rhs,|(a,b)|a.$method(b))
|
||||
}
|
||||
}
|
||||
impl<const N:usize,T:core::ops::$trait<u32,Output=V>,V> core::ops::$trait<u32> for Vector<N,T>{
|
||||
type Output=Vector<N,V>;
|
||||
#[inline]
|
||||
fn $method(self,rhs:u32)->Self::Output{
|
||||
self.map(|t|t.$method(rhs))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_vector_shift_assign_operator {
|
||||
($trait: ident, $method: ident ) => {
|
||||
impl<const N:usize,T:core::ops::$trait<U>,U> core::ops::$trait<Vector<N,U>> for Vector<N,T>{
|
||||
#[inline]
|
||||
fn $method(&mut self,rhs:Vector<N,U>){
|
||||
self.array.iter_mut().zip(rhs.array)
|
||||
.for_each(|(a,b)|a.$method(b))
|
||||
}
|
||||
}
|
||||
impl<const N:usize,T:core::ops::$trait<u32>> core::ops::$trait<u32> for Vector<N,T>{
|
||||
#[inline]
|
||||
fn $method(&mut self,rhs:u32){
|
||||
self.array.iter_mut()
|
||||
.for_each(|t|t.$method(rhs))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
@@ -315,13 +181,11 @@ macro_rules! impl_vector_named_fields {
|
||||
( $struct:ident, $size: expr ) => {
|
||||
impl<T> core::ops::Deref for Vector<$size,T>{
|
||||
type Target=$struct<T>;
|
||||
#[inline]
|
||||
fn deref(&self)->&Self::Target{
|
||||
unsafe{core::mem::transmute(&self.array)}
|
||||
}
|
||||
}
|
||||
impl<T> core::ops::DerefMut for Vector<$size,T>{
|
||||
#[inline]
|
||||
fn deref_mut(&mut self)->&mut Self::Target{
|
||||
unsafe{core::mem::transmute(&mut self.array)}
|
||||
}
|
||||
@@ -333,21 +197,7 @@ macro_rules! impl_vector_named_fields {
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_vector_3 {
|
||||
()=>{
|
||||
impl<T> Vector<3,T>
|
||||
{
|
||||
#[inline]
|
||||
pub fn cross<U,V>(self,rhs:Vector<3,U>)->Vector<3,<V as core::ops::Sub>::Output>
|
||||
where
|
||||
T:core::ops::Mul<U,Output=V>+Copy,
|
||||
U:Copy,
|
||||
V:core::ops::Sub,
|
||||
{
|
||||
Vector::new([
|
||||
self.y*rhs.z-self.z*rhs.y,
|
||||
self.z*rhs.x-self.x*rhs.z,
|
||||
self.x*rhs.y-self.y*rhs.x,
|
||||
])
|
||||
}
|
||||
}
|
||||
#[cfg(feature="fixed_wide")]
|
||||
$crate::impl_vector_wide_3!();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::vector::Vector;
|
||||
|
||||
#[derive(Clone,Copy,Debug,Hash,Eq,PartialEq)]
|
||||
#[derive(Clone,Copy,Hash,Eq,PartialEq)]
|
||||
pub struct Matrix<const X:usize,const Y:usize,T>{
|
||||
pub(crate) array:[[T;X];Y],
|
||||
}
|
||||
@@ -13,5 +13,4 @@ crate::impl_matrix_extend!(3,2);
|
||||
crate::impl_matrix_extend!(3,3);
|
||||
|
||||
//Special case 3x3 matrix operations because I cba to write macros for the arbitrary cases
|
||||
#[cfg(feature="named-fields")]
|
||||
crate::impl_matrix_3x3!();
|
||||
@@ -8,9 +8,9 @@ type Planar64Wide3=fixed_wide::types::I256F256;
|
||||
#[test]
|
||||
fn wide_vec3(){
|
||||
let v=Vector3::from_value(Planar64::from(3));
|
||||
let v1=v*v.x;
|
||||
let v2=v1*v1.y;
|
||||
let v3=v2*v2.z;
|
||||
let v1=v.wide_mul_1_1(v);
|
||||
let v2=v1.wide_mul_2_2(v1);
|
||||
let v3=v2.wide_mul_4_4(v2);
|
||||
|
||||
assert_eq!(v3.array,Vector3::from_value(Planar64Wide3::from(3i128.pow(8))).array);
|
||||
}
|
||||
@@ -18,9 +18,9 @@ fn wide_vec3(){
|
||||
#[test]
|
||||
fn wide_vec3_dot(){
|
||||
let v=Vector3::from_value(Planar64::from(3));
|
||||
let v1=v*v.x;
|
||||
let v2=v1*v1.y;
|
||||
let v3=v2.dot(v2);
|
||||
let v1=v.wide_mul_1_1(v);
|
||||
let v2=v1.wide_mul_2_2(v1);
|
||||
let v3=v2.wide_dot_4_4(v2);
|
||||
|
||||
assert_eq!(v3,Planar64Wide3::from(3i128.pow(8)*3));
|
||||
}
|
||||
@@ -28,9 +28,9 @@ fn wide_vec3_dot(){
|
||||
#[test]
|
||||
fn wide_vec3_length_squared(){
|
||||
let v=Vector3::from_value(Planar64::from(3));
|
||||
let v1=v*v.x;
|
||||
let v2=v1*v1.y;
|
||||
let v3=v2.length_squared();
|
||||
let v1=v.wide_mul_1_1(v);
|
||||
let v2=v1.wide_mul_2_2(v1);
|
||||
let v3=v2.wide_length_squared();
|
||||
|
||||
assert_eq!(v3,Planar64Wide3::from(3i128.pow(8)*3));
|
||||
}
|
||||
@@ -49,7 +49,7 @@ fn wide_matrix_dot(){
|
||||
[Planar64::from(7),Planar64::from(8)],
|
||||
]);
|
||||
// Mat3<Vec4>.dot(Mat4<Vec2>) -> Mat3<Vec2>
|
||||
let m_dot=lhs*rhs;
|
||||
let m_dot=lhs.wide_dot_1_1(rhs);
|
||||
//In[1]:= {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}} . {{1, 2}, {3, 4}, {5, 6}, {7, 8}}
|
||||
//Out[1]= {{50, 60}, {114, 140}, {178, 220}}
|
||||
assert_eq!(
|
||||
@@ -63,7 +63,6 @@ fn wide_matrix_dot(){
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature="named-fields")]
|
||||
fn wide_matrix_det(){
|
||||
let m=Matrix3::new([
|
||||
[Planar64::from(1),Planar64::from(2),Planar64::from(3)],
|
||||
@@ -72,11 +71,10 @@ fn wide_matrix_det(){
|
||||
]);
|
||||
// In[2]:= Det[{{1, 2, 3}, {4, 5, 7}, {6, 8, 9}}]
|
||||
// Out[2]= 7
|
||||
assert_eq!(m.det(),fixed_wide::fixed::Fixed::<3,96>::from(7));
|
||||
assert_eq!(m.wide_det_3x3_1(),fixed_wide::fixed::Fixed::<3,96>::from(7));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature="named-fields")]
|
||||
fn wide_matrix_adjugate(){
|
||||
let m=Matrix3::new([
|
||||
[Planar64::from(1),Planar64::from(2),Planar64::from(3)],
|
||||
@@ -86,7 +84,7 @@ fn wide_matrix_adjugate(){
|
||||
// In[6]:= Adjugate[{{1, 2, 3}, {4, 5, 7}, {6, 8, 9}}]
|
||||
// Out[6]= {{-11, 6, -1}, {6, -9, 5}, {2, 4, -3}}
|
||||
assert_eq!(
|
||||
m.adjugate().array,
|
||||
m.wide_adjugate_3x3_1().array,
|
||||
Matrix3::new([
|
||||
[Planar64Wide1::from(-11),Planar64Wide1::from(6),Planar64Wide1::from(-1)],
|
||||
[Planar64Wide1::from(6),Planar64Wide1::from(-9),Planar64Wide1::from(5)],
|
||||
@@ -3,4 +3,5 @@ mod tests;
|
||||
#[cfg(feature="named-fields")]
|
||||
mod named;
|
||||
|
||||
#[cfg(feature="fixed_wide")]
|
||||
mod fixed_wide;
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::types::{Vector2,Vector3,Matrix4x3,Matrix2x4,Matrix2x3,Matrix3x2};
|
||||
use crate::types::{Vector3,Matrix4x3,Matrix2x4,Matrix2x3};
|
||||
|
||||
#[test]
|
||||
fn test_bool(){
|
||||
@@ -8,28 +8,12 @@ fn test_bool(){
|
||||
assert_eq!(Vector3::new([true,true,true]).all(),true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_length_squared(){
|
||||
assert_eq!(Vector3::new([1,2,3]).length_squared(),14);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arithmetic(){
|
||||
let a=Vector3::new([1,2,3]);
|
||||
assert_eq!((a+a*2).array,Vector3::new([1*3,2*3,3*3]).array);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matrix_transform_vector(){
|
||||
let m=Matrix3x2::new([
|
||||
[1,2,3],
|
||||
[4,5,6],
|
||||
]);
|
||||
let v=Vector3::new([1,2,3]);
|
||||
let transformed=m*v;
|
||||
assert_eq!(transformed.array,Vector2::new([14,32]).array);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matrix_dot(){
|
||||
|
||||
@@ -45,7 +29,7 @@ fn matrix_dot(){
|
||||
[9.0,10.0,11.0,12.0],// [178.0,220.0],
|
||||
]);
|
||||
// Mat3<Vec4>.dot(Mat4<Vec2>) -> Mat3<Vec2>
|
||||
let m_dot=lhs*rhs;
|
||||
let m_dot=lhs.dot(rhs);
|
||||
//In[1]:= {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}} . {{1, 2}, {3, 4}, {5, 6}, {7, 8}}
|
||||
//Out[1]= {{50, 60}, {114, 140}, {178, 220}}
|
||||
assert_eq!(
|
||||
@@ -3,7 +3,7 @@
|
||||
/// v.x += v.z;
|
||||
/// println!("v.x={}",v.x);
|
||||
|
||||
#[derive(Clone,Copy,Debug,Hash,Eq,PartialEq)]
|
||||
#[derive(Clone,Copy,Hash,Eq,PartialEq)]
|
||||
pub struct Vector<const N:usize,T>{
|
||||
pub(crate) array:[T;N],
|
||||
}
|
||||
@@ -15,5 +15,4 @@ crate::impl_vector_extend!(2);
|
||||
crate::impl_vector_extend!(3);
|
||||
|
||||
//cross product
|
||||
#[cfg(feature="named-fields")]
|
||||
crate::impl_vector_3!();
|
||||
@@ -1,15 +0,0 @@
|
||||
[package]
|
||||
name = "linear_ops"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
default=["named-fields"]
|
||||
named-fields=[]
|
||||
deferred-division=["dep:ratio_ops"]
|
||||
|
||||
[dependencies]
|
||||
ratio_ops = { path = "../ratio_ops", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
fixed_wide = { version = "0.1.0", path = "../fixed_wide", features = ["wide-mul"] }
|
||||
1
ratio_ops/.gitignore
vendored
1
ratio_ops/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
/target
|
||||
7
ratio_ops/Cargo.lock
generated
7
ratio_ops/Cargo.lock
generated
@@ -1,7 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "ratio_ops"
|
||||
version = "0.1.0"
|
||||
@@ -1,6 +0,0 @@
|
||||
[package]
|
||||
name = "ratio_ops"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
@@ -1 +0,0 @@
|
||||
pub mod ratio;
|
||||
@@ -1,177 +0,0 @@
|
||||
#[derive(Clone,Copy,Debug,Hash)]
|
||||
pub struct Ratio<Num,Den>{
|
||||
pub num:Num,
|
||||
pub den:Den,
|
||||
}
|
||||
impl<Num,Den> Ratio<Num,Den>{
|
||||
#[inline(always)]
|
||||
pub const fn new(num:Num,den:Den)->Self{
|
||||
Self{num,den}
|
||||
}
|
||||
}
|
||||
|
||||
/// The actual divide implementation, Div is replaced with a Ratio constructor
|
||||
pub trait Divide<Rhs=Self>{
|
||||
type Output;
|
||||
fn divide(self,rhs:Rhs)->Self::Output;
|
||||
}
|
||||
|
||||
impl<Num,Den> Ratio<Num,Den>
|
||||
where
|
||||
Num:Divide<Den>,
|
||||
{
|
||||
#[inline]
|
||||
pub fn divide(self)-><Num as Divide<Den>>::Output{
|
||||
self.num.divide(self.den)
|
||||
}
|
||||
}
|
||||
|
||||
//take care to use the ratio methods to avoid nested ratios
|
||||
|
||||
impl<LhsNum,LhsDen> Ratio<LhsNum,LhsDen>{
|
||||
#[inline]
|
||||
pub fn mul_ratio<RhsNum,RhsDen>(self,rhs:Ratio<RhsNum,RhsDen>)->Ratio<<LhsNum as core::ops::Mul<RhsNum>>::Output,<LhsDen as core::ops::Mul<RhsDen>>::Output>
|
||||
where
|
||||
LhsNum:core::ops::Mul<RhsNum>,
|
||||
LhsDen:core::ops::Mul<RhsDen>,
|
||||
{
|
||||
Ratio::new(self.num*rhs.num,self.den*rhs.den)
|
||||
}
|
||||
#[inline]
|
||||
pub fn div_ratio<RhsNum,RhsDen>(self,rhs:Ratio<RhsNum,RhsDen>)->Ratio<<LhsNum as core::ops::Mul<RhsDen>>::Output,<LhsDen as core::ops::Mul<RhsNum>>::Output>
|
||||
where
|
||||
LhsNum:core::ops::Mul<RhsDen>,
|
||||
LhsDen:core::ops::Mul<RhsNum>,
|
||||
{
|
||||
Ratio::new(self.num*rhs.den,self.den*rhs.num)
|
||||
}
|
||||
}
|
||||
macro_rules! impl_ratio_method {
|
||||
($trait:ident, $method:ident, $ratio_method:ident) => {
|
||||
impl<LhsNum,LhsDen> Ratio<LhsNum,LhsDen>{
|
||||
#[inline]
|
||||
pub fn $ratio_method<RhsNum,RhsDen,LhsCrossMul,RhsCrossMul>(self,rhs:Ratio<RhsNum,RhsDen>)->Ratio<<LhsCrossMul as core::ops::$trait<RhsCrossMul>>::Output,<LhsDen as core::ops::Mul<RhsDen>>::Output>
|
||||
where
|
||||
LhsNum:core::ops::Mul<RhsDen,Output=LhsCrossMul>,
|
||||
LhsDen:core::ops::Mul<RhsNum,Output=RhsCrossMul>,
|
||||
LhsDen:core::ops::Mul<RhsDen>,
|
||||
LhsDen:Copy,
|
||||
RhsDen:Copy,
|
||||
LhsCrossMul:core::ops::$trait<RhsCrossMul>,
|
||||
{
|
||||
Ratio::new((self.num*rhs.den).$method(self.den*rhs.num),self.den*rhs.den)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
impl_ratio_method!(Add,add,add_ratio);
|
||||
impl_ratio_method!(Sub,sub,sub_ratio);
|
||||
impl_ratio_method!(Rem,rem,rem_ratio);
|
||||
|
||||
/* generic rhs mul is not possible!
|
||||
impl<Lhs,RhsNum,RhsDen> core::ops::Mul<Ratio<RhsNum,RhsDen>> for Lhs
|
||||
where
|
||||
Lhs:core::ops::Mul<RhsNum>,
|
||||
{
|
||||
type Output=Ratio<<Lhs as core::ops::Mul<RhsNum>>::Output,RhsDen>;
|
||||
#[inline]
|
||||
fn mul(self,rhs:Ratio<RhsNum,RhsDen>)->Self::Output{
|
||||
Ratio::new(self*rhs.num,rhs.den)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
//operators
|
||||
|
||||
impl<LhsNum,LhsDen> core::ops::Neg for Ratio<LhsNum,LhsDen>
|
||||
where
|
||||
LhsNum:core::ops::Neg,
|
||||
{
|
||||
type Output=Ratio<<LhsNum as core::ops::Neg>::Output,LhsDen>;
|
||||
#[inline]
|
||||
fn neg(self)->Self::Output{
|
||||
Ratio::new(-self.num,self.den)
|
||||
}
|
||||
}
|
||||
impl<LhsNum,LhsDen,Rhs> core::ops::Mul<Rhs> for Ratio<LhsNum,LhsDen>
|
||||
where
|
||||
LhsNum:core::ops::Mul<Rhs>,
|
||||
{
|
||||
type Output=Ratio<<LhsNum as core::ops::Mul<Rhs>>::Output,LhsDen>;
|
||||
#[inline]
|
||||
fn mul(self,rhs:Rhs)->Self::Output{
|
||||
Ratio::new(self.num*rhs,self.den)
|
||||
}
|
||||
}
|
||||
impl<LhsNum,LhsDen,Rhs> core::ops::Div<Rhs> for Ratio<LhsNum,LhsDen>
|
||||
where
|
||||
LhsDen:core::ops::Mul<Rhs>,
|
||||
{
|
||||
type Output=Ratio<LhsNum,<LhsDen as core::ops::Mul<Rhs>>::Output>;
|
||||
#[inline]
|
||||
fn div(self,rhs:Rhs)->Self::Output{
|
||||
Ratio::new(self.num,self.den*rhs)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_ratio_operator {
|
||||
($trait:ident, $method:ident) => {
|
||||
impl<LhsNum,LhsDen,Rhs,Intermediate> core::ops::$trait<Rhs> for Ratio<LhsNum,LhsDen>
|
||||
where
|
||||
LhsNum:core::ops::$trait<Intermediate>,
|
||||
LhsDen:Copy,
|
||||
Rhs:core::ops::Mul<LhsDen,Output=Intermediate>,
|
||||
{
|
||||
type Output=Ratio<<LhsNum as core::ops::$trait<Intermediate>>::Output,LhsDen>;
|
||||
#[inline]
|
||||
fn $method(self,rhs:Rhs)->Self::Output{
|
||||
Ratio::new(self.num.$method(rhs*self.den),self.den)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_ratio_operator!(Add,add);
|
||||
impl_ratio_operator!(Sub,sub);
|
||||
impl_ratio_operator!(Rem,rem);
|
||||
|
||||
//assign operators
|
||||
|
||||
impl<LhsNum,LhsDen,Rhs> core::ops::MulAssign<Rhs> for Ratio<LhsNum,LhsDen>
|
||||
where
|
||||
LhsNum:core::ops::MulAssign<Rhs>,
|
||||
{
|
||||
#[inline]
|
||||
fn mul_assign(&mut self,rhs:Rhs){
|
||||
self.num*=rhs;
|
||||
}
|
||||
}
|
||||
impl<LhsNum,LhsDen,Rhs> core::ops::DivAssign<Rhs> for Ratio<LhsNum,LhsDen>
|
||||
where
|
||||
LhsDen:core::ops::MulAssign<Rhs>,
|
||||
{
|
||||
#[inline]
|
||||
fn div_assign(&mut self,rhs:Rhs){
|
||||
self.den*=rhs;
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_ratio_assign_operator {
|
||||
($trait:ident, $method:ident) => {
|
||||
impl<LhsNum,LhsDen,Rhs> core::ops::$trait<Rhs> for Ratio<LhsNum,LhsDen>
|
||||
where
|
||||
LhsNum:core::ops::$trait,
|
||||
LhsDen:Copy,
|
||||
Rhs:core::ops::Mul<LhsDen,Output=LhsNum>,
|
||||
{
|
||||
#[inline]
|
||||
fn $method(&mut self,rhs:Rhs){
|
||||
self.num.$method(rhs*self.den)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_ratio_assign_operator!(AddAssign,add_assign);
|
||||
impl_ratio_assign_operator!(SubAssign,sub_assign);
|
||||
impl_ratio_assign_operator!(RemAssign,rem_assign);
|
||||
Reference in New Issue
Block a user