Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1a56128a79 | |||
| 6335b1da47 | |||
| 8d5fc1ae48 | |||
| 67c30b8535 | |||
| 95651d7091 | |||
| 91b378aa43 | |||
| ac7d9f5c3b | |||
| b45d93a7dc | |||
| 6549305c9f | |||
| 6ea9eff844 | |||
| e684fb421e | |||
| 8ba76c7a00 | |||
| 3d3eb966a4 | |||
| 491de52f17 | |||
| 69da2c52a4 | |||
| 9f6dffafda | |||
| 446de71c30 | |||
| d47eaa423e | |||
| e604ce83e9 | |||
| ac250e9d84 | |||
| 617952c1e3 | |||
| 9f9e8c793b | |||
| 1f6594468d | |||
| cc3cb35309 | |||
| a923a6b5d1 | |||
| 68d1c23cfa | |||
| 8aa7da6be7 | |||
| 0be0dd5c6f | |||
| f4ab9403a4 | |||
| 67ac4cf7ff | |||
| 002d3d9eac | |||
| e1368962c1 | |||
| 4ae391e9fd |
22
deferred_division/Cargo.lock
generated
22
deferred_division/Cargo.lock
generated
@@ -2,13 +2,35 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "bnum"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e31ea183f6ee62ac8b8a8cf7feddd766317adfb13ff469de57ce033efd6a790"
|
||||
|
||||
[[package]]
|
||||
name = "deferred_division"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"fixed_wide",
|
||||
"fixed_wide_traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fixed_wide"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bnum",
|
||||
"fixed_wide_traits",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fixed_wide_traits"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
|
||||
@@ -9,3 +9,6 @@ fixed_wide_traits=["dep:fixed_wide_traits"]
|
||||
|
||||
[dependencies]
|
||||
fixed_wide_traits = { version = "0.1.0", path = "../fixed_wide_traits", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
fixed_wide = { version = "0.1.0", path = "../fixed_wide" }
|
||||
|
||||
@@ -1,10 +1,172 @@
|
||||
use std::ops::Mul;
|
||||
|
||||
#[derive(Clone,Copy,Debug,Hash)]
|
||||
pub struct Ratio<Num,Den>{
|
||||
pub(crate)num:Num,
|
||||
pub(crate)den:Den,
|
||||
}
|
||||
//this trait is like a constructor for Ratio
|
||||
pub trait DeferredDiv<Rhs=Self>{
|
||||
type Output;
|
||||
fn deferred_div(self,rhs:Rhs)->Self::Output;
|
||||
impl<Num,Den> Ratio<Num,Den>{
|
||||
pub const fn new(num:Num,den:Den)->Self{
|
||||
Self{num,den}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Num,Den,Rhs> PartialEq<Rhs> for Ratio<Num,Den>
|
||||
where
|
||||
Den:Copy,
|
||||
Rhs:Mul<Den>+Copy,
|
||||
Num:PartialEq<<Rhs as Mul<Den>>::Output>
|
||||
{
|
||||
fn eq(&self,rhs:&Rhs)->bool{
|
||||
self.num.eq(&rhs.mul(self.den))
|
||||
}
|
||||
}
|
||||
/*
|
||||
//You can't do Ratio==Ratio I guess
|
||||
impl<Num,Den> Eq for Ratio<Num,Den>
|
||||
where
|
||||
Num:Mul<Den>,
|
||||
<Num as Mul<Den>>::Output:PartialEq
|
||||
{}
|
||||
*/
|
||||
|
||||
// num/den == rhs
|
||||
// num == rhs * den
|
||||
|
||||
impl<Num,Den,Rhs> PartialOrd<Rhs> for Ratio<Num,Den>
|
||||
where
|
||||
Den:Copy,
|
||||
Rhs:Mul<Den>+Copy,
|
||||
Num:PartialOrd<<Rhs as Mul<Den>>::Output>
|
||||
{
|
||||
fn partial_cmp(&self,rhs:&Rhs)->Option<std::cmp::Ordering>{
|
||||
self.num.partial_cmp(&rhs.mul(self.den))
|
||||
}
|
||||
}
|
||||
/*
|
||||
impl<Den,Rhs> Ord for Ratio<<Rhs as Mul<Den>>::Output,Den>
|
||||
where
|
||||
Rhs:Mul<Den>,
|
||||
Rhs:Ord,
|
||||
<Rhs as Mul<Den>>::Output:Ord,
|
||||
{
|
||||
fn cmp(&self,other:&Rhs)->std::cmp::Ordering{
|
||||
self.num.cmp(&other.mul(self.den))
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
impl<NewNum,Num:std::ops::Neg<Output=NewNum>,Den> std::ops::Neg for Ratio<Num,Den>{
|
||||
type Output=Ratio<NewNum,Den>;
|
||||
fn neg(self)->Self::Output{
|
||||
Ratio{
|
||||
num:self.num.neg(),
|
||||
den:self.den,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// num/den + rhs == new_num/den
|
||||
// new_num = num + rhs * den
|
||||
|
||||
macro_rules! impl_operator {
|
||||
($struct:ident,$trait:ident,$method:ident)=>{
|
||||
impl<Num,Den,Rhs> core::ops::$trait<Rhs> for $struct<Num,Den>
|
||||
where
|
||||
Den:Copy,
|
||||
Rhs:Mul<Den>,
|
||||
Num:core::ops::$trait<<Rhs as Mul<Den>>::Output>,
|
||||
{
|
||||
type Output=$struct<<Num as core::ops::$trait<<Rhs as Mul<Den>>::Output>>::Output,Den>;
|
||||
|
||||
fn $method(self,rhs:Rhs)->Self::Output{
|
||||
$struct{
|
||||
num:self.num.$method(rhs.mul(self.den)),
|
||||
den:self.den,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<Num,Den,Lhs> core::ops::$trait<$struct<Num,Den>> for Lhs
|
||||
where
|
||||
Den:Copy,
|
||||
Lhs:Mul<Den>,
|
||||
<Lhs as Mul<Den>>::Output:core::ops::$trait<Num>,
|
||||
{
|
||||
type Output=$struct<<<Lhs as Mul<Den>>::Output as core::ops::$trait<Num>>::Output,Den>;
|
||||
|
||||
fn $method(self,rhs:$struct<Num,Den>)->Self::Output{
|
||||
$struct{
|
||||
num:self.mul(rhs.den).$method(rhs.num),
|
||||
den:rhs.den,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
macro_rules! impl_assign_operator{
|
||||
($struct:ident,$trait:ident,$method:ident)=>{
|
||||
impl<Num,Den,Rhs> core::ops::$trait<Rhs> for $struct<Num,Den>
|
||||
where
|
||||
Den:Copy,
|
||||
Rhs:Mul<Den>,
|
||||
Num:core::ops::$trait<<Rhs as Mul<Den>>::Output>,
|
||||
{
|
||||
fn $method(&mut self,rhs:Rhs){
|
||||
self.num.$method(rhs.mul(self.den));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Impl arithmetic operators
|
||||
impl_assign_operator!(Ratio,AddAssign,add_assign);
|
||||
impl_operator!(Ratio,Add,add);
|
||||
impl_assign_operator!(Ratio,SubAssign,sub_assign);
|
||||
impl_operator!(Ratio,Sub,sub);
|
||||
// num/den % rhs == new_num/den
|
||||
// new_num = num % (rhs * den)
|
||||
impl_assign_operator!(Ratio,RemAssign,rem_assign);
|
||||
impl_operator!(Ratio,Rem,rem);
|
||||
|
||||
//mul and div is special
|
||||
impl<Num,Den,Rhs> Mul<Rhs> for Ratio<Num,Den>
|
||||
where
|
||||
Num:Mul<Rhs>,
|
||||
{
|
||||
type Output=Ratio<<Num as Mul<Rhs>>::Output,Den>;
|
||||
fn mul(self,rhs:Rhs)->Self::Output{
|
||||
Ratio{
|
||||
num:self.num.mul(rhs),
|
||||
den:self.den,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<Num,Den,Rhs> core::ops::MulAssign<Rhs> for Ratio<Num,Den>
|
||||
where
|
||||
Num:core::ops::MulAssign<Rhs>,
|
||||
{
|
||||
fn mul_assign(&mut self,rhs:Rhs){
|
||||
self.num.mul_assign(rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl<Num,Den,Rhs> core::ops::Div<Rhs> for Ratio<Num,Den>
|
||||
where
|
||||
Den:Mul<Rhs>,
|
||||
{
|
||||
type Output=Ratio<Num,<Den as Mul<Rhs>>::Output>;
|
||||
fn div(self,rhs:Rhs)->Self::Output{
|
||||
Ratio{
|
||||
num:self.num,
|
||||
den:self.den.mul(rhs),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<Num,Den,Rhs> core::ops::DivAssign<Rhs> for Ratio<Num,Den>
|
||||
where
|
||||
Den:core::ops::MulAssign<Rhs>,
|
||||
{
|
||||
fn div_assign(&mut self,rhs:Rhs){
|
||||
self.den.mul_assign(rhs);
|
||||
}
|
||||
}
|
||||
|
||||
4
deferred_division/src/tests/mod.rs
Normal file
4
deferred_division/src/tests/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
mod tests;
|
||||
|
||||
#[cfg(feature="fixed_wide_traits")]
|
||||
mod wide;
|
||||
22
deferred_division/src/tests/tests.rs
Normal file
22
deferred_division/src/tests/tests.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
use crate::ratio::Ratio;
|
||||
|
||||
#[test]
|
||||
fn ratio(){
|
||||
let r=Ratio::new(5,3);
|
||||
let a=r%1;
|
||||
assert_eq!(a.num,2);
|
||||
assert_eq!(a.den,3);
|
||||
let b=r*2;
|
||||
assert_eq!(b.num,10);
|
||||
assert_eq!(b.den,3);
|
||||
let c=r/2;
|
||||
assert_eq!(c.num,5);
|
||||
assert_eq!(c.den,6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_ratio_cmp(){
|
||||
let a=Ratio::new(5,3);
|
||||
let b=Ratio::new(1,3);
|
||||
assert_eq!(a+b,2);
|
||||
}
|
||||
15
deferred_division/src/tests/wide.rs
Normal file
15
deferred_division/src/tests/wide.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
use crate::ratio::Ratio;
|
||||
use fixed_wide_traits::wide::{WideMul,WideDiv};
|
||||
use fixed_wide::types::I32F32;
|
||||
use fixed_wide::types::I64F64;
|
||||
|
||||
#[test]
|
||||
fn ratio(){
|
||||
let r=Ratio::new(I32F32::from(5),I32F32::from(3));
|
||||
let a=r.wide_mul(I32F32::from(7)>>2);
|
||||
assert_eq!(a.num,I64F64::from(7*5)>>2);
|
||||
assert_eq!(a.den,I32F32::from(3));
|
||||
let a=r.wide_div(I32F32::from(7)>>2);
|
||||
assert_eq!(a.num,I32F32::from(5));
|
||||
assert_eq!(a.den,I64F64::from(3*7)>>2);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::ops::{Add,Mul};
|
||||
use crate::ratio::Ratio;
|
||||
use fixed_wide_traits::wide::{WideMul,WideDiv};
|
||||
use fixed_wide_traits::wide::{WideMul,WideDiv,WideDot,WideCross};
|
||||
|
||||
impl<Num,Den:Copy> Ratio<Num,Den>
|
||||
{
|
||||
@@ -25,18 +25,25 @@ impl<Num,Den:Copy> Ratio<Num,Den>
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<Num,Den,T> WideMul<T> for Ratio<Num,Den>
|
||||
where
|
||||
Num:WideMul<T>,
|
||||
{
|
||||
type Output=Ratio<<Num as WideMul<T>>::Output,Den>;
|
||||
fn wide_mul(self,rhs:T)->Ratio<<Num as WideMul<T>>::Output,Den>{
|
||||
Ratio{
|
||||
num:self.num.wide_mul(rhs),
|
||||
den:self.den,
|
||||
macro_rules! impl_mul_operator {
|
||||
($struct:ident,$trait:ident,$method:ident)=>{
|
||||
impl<Num,Den,Rhs> $trait<Rhs> for $struct<Num,Den>
|
||||
where
|
||||
Num:$trait<Rhs>,
|
||||
{
|
||||
type Output=$struct<<Num as $trait<Rhs>>::Output,Den>;
|
||||
fn $method(self,rhs:Rhs)->Self::Output{
|
||||
$struct{
|
||||
num:self.num.$method(rhs),
|
||||
den:self.den,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl_mul_operator!(Ratio,WideMul,wide_mul);
|
||||
impl_mul_operator!(Ratio,WideDot,wide_dot);
|
||||
impl_mul_operator!(Ratio,WideCross,wide_cross);
|
||||
impl<Num,Den,T> WideDiv<T> for Ratio<Num,Den>
|
||||
where
|
||||
Den:WideMul<T>,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use bnum::BInt;
|
||||
use bnum::{BInt,cast::As};
|
||||
use typenum::Unsigned;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
@@ -9,18 +9,35 @@ pub struct Fixed<const CHUNKS:usize,Frac>{
|
||||
}
|
||||
|
||||
impl<const CHUNKS:usize,Frac:Unsigned> Fixed<CHUNKS,Frac>{
|
||||
pub const MAX:Self=Self{bits:BInt::<CHUNKS>::MAX,frac:PhantomData};
|
||||
pub const MIN:Self=Self{bits:BInt::<CHUNKS>::MIN,frac:PhantomData};
|
||||
pub const ZERO:Self=Self{bits:BInt::<CHUNKS>::ZERO,frac:PhantomData};
|
||||
pub const EPSILON:Self=Self{bits:BInt::<CHUNKS>::ONE,frac:PhantomData};
|
||||
pub const NEG_EPSILON:Self=Self{bits:BInt::<CHUNKS>::NEG_ONE,frac:PhantomData};
|
||||
pub const ONE:Self=Self{bits:BInt::<CHUNKS>::ONE.shl(Frac::U32),frac:PhantomData};
|
||||
pub const TWO:Self=Self{bits:BInt::<CHUNKS>::TWO.shl(Frac::U32),frac:PhantomData};
|
||||
pub const HALF:Self=Self{bits:BInt::<CHUNKS>::ONE.shl(Frac::U32-1),frac:PhantomData};
|
||||
pub const NEG_ONE:Self=Self{bits:BInt::<CHUNKS>::NEG_ONE.shl(Frac::U32),frac:PhantomData};
|
||||
pub const NEG_TWO:Self=Self{bits:BInt::<CHUNKS>::NEG_TWO.shl(Frac::U32),frac:PhantomData};
|
||||
pub const NEG_HALF:Self=Self{bits:BInt::<CHUNKS>::NEG_ONE.shl(Frac::U32-1),frac:PhantomData};
|
||||
pub const fn from_bits(bits:BInt::<CHUNKS>)->Self{
|
||||
Self{
|
||||
bits,
|
||||
frac:PhantomData,
|
||||
}
|
||||
}
|
||||
pub const fn to_bits(self)->BInt<CHUNKS>{
|
||||
self.bits
|
||||
}
|
||||
}
|
||||
|
||||
impl<const CHUNKS:usize,FracDst:Unsigned,T> From<T> for Fixed<CHUNKS,FracDst>
|
||||
impl<const CHUNKS:usize,Frac:Unsigned,T> From<T> for Fixed<CHUNKS,Frac>
|
||||
where
|
||||
BInt<CHUNKS>:From<T>
|
||||
{
|
||||
fn from(value:T)->Self{
|
||||
Self{
|
||||
bits:BInt::<{CHUNKS}>::from(value)<<FracDst::U32,
|
||||
bits:BInt::<{CHUNKS}>::from(value)<<Frac::U32,
|
||||
frac:PhantomData,
|
||||
}
|
||||
}
|
||||
@@ -54,72 +71,224 @@ impl<const CHUNKS:usize,Frac> std::ops::Neg for Fixed<CHUNKS,Frac>{
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_operator {
|
||||
macro_rules! impl_additive_operator {
|
||||
( $struct: ident, $trait: ident, $method: ident, $output: ty ) => {
|
||||
impl<const CHUNKS:usize,Frac> core::ops::$trait for $struct<CHUNKS,Frac>{
|
||||
type Output = $output;
|
||||
impl<const CHUNKS:usize,Frac> core::ops::$trait for $struct<CHUNKS,Frac>{
|
||||
type Output = $output;
|
||||
|
||||
fn $method(self, other: Self) -> Self::Output {
|
||||
Self {
|
||||
bits:self.bits.$method(other.bits),
|
||||
frac:PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
fn $method(self, other: Self) -> Self::Output {
|
||||
Self {
|
||||
bits:self.bits.$method(other.bits),
|
||||
frac:PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<const CHUNKS:usize,Frac:Unsigned,U> core::ops::$trait<U> for $struct<CHUNKS,Frac>
|
||||
where
|
||||
BInt::<CHUNKS>:From<U>,
|
||||
{
|
||||
type Output = $output;
|
||||
|
||||
fn $method(self, other: U) -> Self::Output {
|
||||
Self {
|
||||
bits:self.bits.$method(BInt::<CHUNKS>::from(other)<<Frac::U32),
|
||||
frac:PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
macro_rules! impl_assign_operator {
|
||||
( $struct: ident, $trait: ident, $method: ident ) => {
|
||||
impl<const CHUNKS:usize,Frac> core::ops::$trait for $struct<CHUNKS,Frac>{
|
||||
fn $method(&mut self, other: Self) {
|
||||
self.bits.$method(other.bits);
|
||||
}
|
||||
}
|
||||
};
|
||||
macro_rules! impl_additive_assign_operator {
|
||||
( $struct: ident, $trait: ident, $method: ident ) => {
|
||||
impl<const CHUNKS:usize,Frac> core::ops::$trait for $struct<CHUNKS,Frac>{
|
||||
fn $method(&mut self, other: Self) {
|
||||
self.bits.$method(other.bits);
|
||||
}
|
||||
}
|
||||
impl<const CHUNKS:usize,Frac:Unsigned,U> core::ops::$trait<U> for $struct<CHUNKS,Frac>
|
||||
where
|
||||
BInt::<CHUNKS>:From<U>,
|
||||
{
|
||||
fn $method(&mut self, other: U) {
|
||||
self.bits.$method(BInt::<CHUNKS>::from(other)<<Frac::U32);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Impl arithmetic pperators
|
||||
impl_assign_operator!( Fixed, AddAssign, add_assign );
|
||||
impl_operator!( Fixed, Add, add, Self );
|
||||
impl_assign_operator!( Fixed, SubAssign, sub_assign );
|
||||
impl_operator!( Fixed, Sub, sub, Self );
|
||||
impl_assign_operator!( Fixed, MulAssign, mul_assign );
|
||||
impl_operator!( Fixed, Mul, mul, Self );
|
||||
impl_assign_operator!( Fixed, DivAssign, div_assign );
|
||||
impl_operator!( Fixed, Div, div, Self );
|
||||
impl_assign_operator!( Fixed, RemAssign, rem_assign );
|
||||
impl_operator!( Fixed, Rem, rem, Self );
|
||||
impl_additive_assign_operator!( Fixed, AddAssign, add_assign );
|
||||
impl_additive_operator!( Fixed, Add, add, Self );
|
||||
impl_additive_assign_operator!( Fixed, SubAssign, sub_assign );
|
||||
impl_additive_operator!( Fixed, Sub, sub, Self );
|
||||
impl_additive_assign_operator!( Fixed, RemAssign, rem_assign );
|
||||
impl_additive_operator!( Fixed, Rem, rem, Self );
|
||||
|
||||
// Impl bitwise operators
|
||||
impl_assign_operator!( Fixed, BitAndAssign, bitand_assign );
|
||||
impl_operator!( Fixed, BitAnd, bitand, Self );
|
||||
impl_assign_operator!( Fixed, BitOrAssign, bitor_assign );
|
||||
impl_operator!( Fixed, BitOr, bitor, Self );
|
||||
impl_assign_operator!( Fixed, BitXorAssign, bitxor_assign );
|
||||
impl_operator!( Fixed, BitXor, bitxor, Self );
|
||||
impl_additive_assign_operator!( Fixed, BitAndAssign, bitand_assign );
|
||||
impl_additive_operator!( Fixed, BitAnd, bitand, Self );
|
||||
impl_additive_assign_operator!( Fixed, BitOrAssign, bitor_assign );
|
||||
impl_additive_operator!( Fixed, BitOr, bitor, Self );
|
||||
impl_additive_assign_operator!( Fixed, BitXorAssign, bitxor_assign );
|
||||
impl_additive_operator!( Fixed, BitXor, bitxor, Self );
|
||||
|
||||
macro_rules! impl_multiply_operator_const {
|
||||
( $width:expr, $struct: ident, $trait: ident, $method: ident, $output: ty ) => {
|
||||
impl<Frac:Unsigned> core::ops::$trait for $struct<$width,Frac>{
|
||||
type Output = $output;
|
||||
|
||||
fn $method(self, other: Self) -> Self::Output {
|
||||
//this can be done better but that is a job for later
|
||||
let lhs=self.bits.as_::<BInt::<{$width*2}>>();
|
||||
let rhs=other.bits.as_::<BInt::<{$width*2}>>();
|
||||
Self {
|
||||
bits:lhs.mul(rhs).shr(Frac::U32).as_(),
|
||||
frac:PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
macro_rules! impl_multiply_assign_operator_const {
|
||||
( $width:expr, $struct: ident, $trait: ident, $method: ident ) => {
|
||||
impl<Frac> core::ops::$trait for $struct<$width,Frac>{
|
||||
fn $method(&mut self, other: Self) {
|
||||
self.bits.$method(other.bits);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_divide_operator_const {
|
||||
( $width:expr, $struct: ident, $trait: ident, $method: ident, $output: ty ) => {
|
||||
impl<Frac:Unsigned> core::ops::$trait for $struct<$width,Frac>{
|
||||
type Output = $output;
|
||||
|
||||
fn $method(self, other: Self) -> Self::Output {
|
||||
//this can be done better but that is a job for later
|
||||
//this only needs to be $width+Frac::U32/64+1 but MUH CONST GENERICS!!!!!
|
||||
let lhs=self.bits.as_::<BInt::<{$width*2}>>().shl(Frac::U32);
|
||||
let rhs=other.bits.as_::<BInt::<{$width*2}>>();
|
||||
Self {
|
||||
bits:lhs.div(rhs).as_(),
|
||||
frac:PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
macro_rules! impl_divide_assign_operator_const {
|
||||
( $width:expr, $struct: ident, $trait: ident, $method: ident ) => {
|
||||
impl<Frac> core::ops::$trait for $struct<$width,Frac>{
|
||||
fn $method(&mut self, other: Self) {
|
||||
self.bits.$method(other.bits);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_multiplicatave_operator {
|
||||
( $struct: ident, $trait: ident, $method: ident, $output: ty ) => {
|
||||
impl<const CHUNKS:usize,Frac,U> core::ops::$trait<U> for $struct<CHUNKS,Frac>
|
||||
where
|
||||
BInt::<CHUNKS>:From<U>+core::ops::$trait,
|
||||
{
|
||||
type Output = $output;
|
||||
|
||||
fn $method(self, other: U) -> Self::Output {
|
||||
Self {
|
||||
bits:self.bits.$method(BInt::<CHUNKS>::from(other)),
|
||||
frac:PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
macro_rules! impl_multiplicatave_assign_operator {
|
||||
( $struct: ident, $trait: ident, $method: ident ) => {
|
||||
impl<const CHUNKS:usize,Frac,U> core::ops::$trait<U> for $struct<CHUNKS,Frac>
|
||||
where
|
||||
BInt::<CHUNKS>:From<U>+core::ops::$trait,
|
||||
{
|
||||
fn $method(&mut self, other: U) {
|
||||
self.bits.$method(BInt::<CHUNKS>::from(other));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_operator_16 {
|
||||
( $macro: ident, $struct: ident, $trait: ident, $method: ident, $output: ty ) => {
|
||||
$macro!(1,$struct,$trait,$method,$output);
|
||||
$macro!(2,$struct,$trait,$method,$output);
|
||||
$macro!(3,$struct,$trait,$method,$output);
|
||||
$macro!(4,$struct,$trait,$method,$output);
|
||||
$macro!(5,$struct,$trait,$method,$output);
|
||||
$macro!(6,$struct,$trait,$method,$output);
|
||||
$macro!(7,$struct,$trait,$method,$output);
|
||||
$macro!(8,$struct,$trait,$method,$output);
|
||||
$macro!(9,$struct,$trait,$method,$output);
|
||||
$macro!(10,$struct,$trait,$method,$output);
|
||||
$macro!(11,$struct,$trait,$method,$output);
|
||||
$macro!(12,$struct,$trait,$method,$output);
|
||||
$macro!(13,$struct,$trait,$method,$output);
|
||||
$macro!(14,$struct,$trait,$method,$output);
|
||||
$macro!(15,$struct,$trait,$method,$output);
|
||||
$macro!(16,$struct,$trait,$method,$output);
|
||||
}
|
||||
}
|
||||
macro_rules! impl_assign_operator_16 {
|
||||
( $macro: ident, $struct: ident, $trait: ident, $method: ident ) => {
|
||||
$macro!(1,$struct,$trait,$method);
|
||||
$macro!(2,$struct,$trait,$method);
|
||||
$macro!(3,$struct,$trait,$method);
|
||||
$macro!(4,$struct,$trait,$method);
|
||||
$macro!(5,$struct,$trait,$method);
|
||||
$macro!(6,$struct,$trait,$method);
|
||||
$macro!(7,$struct,$trait,$method);
|
||||
$macro!(8,$struct,$trait,$method);
|
||||
$macro!(9,$struct,$trait,$method);
|
||||
$macro!(10,$struct,$trait,$method);
|
||||
$macro!(11,$struct,$trait,$method);
|
||||
$macro!(12,$struct,$trait,$method);
|
||||
$macro!(13,$struct,$trait,$method);
|
||||
$macro!(14,$struct,$trait,$method);
|
||||
$macro!(15,$struct,$trait,$method);
|
||||
$macro!(16,$struct,$trait,$method);
|
||||
}
|
||||
}
|
||||
|
||||
impl_assign_operator_16!( impl_multiply_assign_operator_const, Fixed, MulAssign, mul_assign );
|
||||
impl_operator_16!( impl_multiply_operator_const, Fixed, Mul, mul, Self );
|
||||
impl_assign_operator_16!( impl_divide_assign_operator_const, Fixed, DivAssign, div_assign );
|
||||
impl_operator_16!( impl_divide_operator_const, Fixed, Div, div, Self );
|
||||
impl_multiplicatave_assign_operator!( Fixed, MulAssign, mul_assign );
|
||||
impl_multiplicatave_operator!( Fixed, Mul, mul, Self );
|
||||
impl_multiplicatave_assign_operator!( Fixed, DivAssign, div_assign );
|
||||
impl_multiplicatave_operator!( Fixed, Div, div, Self );
|
||||
|
||||
macro_rules! impl_shift_operator {
|
||||
( $struct: ident, $trait: ident, $method: ident, $output: ty ) => {
|
||||
impl<const CHUNKS:usize,Frac> core::ops::$trait<u32> for $struct<CHUNKS,Frac>{
|
||||
type Output = $output;
|
||||
impl<const CHUNKS:usize,Frac> core::ops::$trait<u32> for $struct<CHUNKS,Frac>{
|
||||
type Output = $output;
|
||||
|
||||
fn $method(self, other: u32) -> Self::Output {
|
||||
Self {
|
||||
bits:self.bits.$method(other),
|
||||
frac:PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
fn $method(self, other: u32) -> Self::Output {
|
||||
Self {
|
||||
bits:self.bits.$method(other),
|
||||
frac:PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
macro_rules! impl_shift_assign_operator {
|
||||
( $struct: ident, $trait: ident, $method: ident ) => {
|
||||
impl<const CHUNKS:usize,Frac> core::ops::$trait<u32> for $struct<CHUNKS,Frac>{
|
||||
fn $method(&mut self, other: u32) {
|
||||
self.bits.$method(other);
|
||||
}
|
||||
}
|
||||
};
|
||||
( $struct: ident, $trait: ident, $method: ident ) => {
|
||||
impl<const CHUNKS:usize,Frac> core::ops::$trait<u32> for $struct<CHUNKS,Frac>{
|
||||
fn $method(&mut self, other: u32) {
|
||||
self.bits.$method(other);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
impl_shift_assign_operator!( Fixed, ShlAssign, shl_assign );
|
||||
impl_shift_operator!( Fixed, Shl, shl, Self );
|
||||
|
||||
@@ -24,11 +24,11 @@ macro_rules! impl_wide_mul {
|
||||
}
|
||||
|
||||
macro_rules! impl_wide_mul_all {
|
||||
($(($x:expr, $y:expr)),*) => {
|
||||
$(
|
||||
impl_wide_mul!($x, $y);
|
||||
)*
|
||||
};
|
||||
($(($x:expr, $y:expr)),*) => {
|
||||
$(
|
||||
impl_wide_mul!($x, $y);
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
//const generics sidestepped wahoo
|
||||
@@ -42,3 +42,70 @@ impl_wide_mul_all!(
|
||||
(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)
|
||||
);
|
||||
impl<const SRC:usize,Frac> Fixed<SRC,Frac>{
|
||||
pub fn widen<const DST:usize>(self)->Fixed<DST,Frac>{
|
||||
Fixed{
|
||||
bits:self.bits.as_::<BInt<DST>>(),
|
||||
frac:PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<const CHUNKS:usize,Frac:Unsigned> Fixed<CHUNKS,Frac>
|
||||
where
|
||||
Fixed::<CHUNKS,Frac>:WideMul,
|
||||
<Fixed::<CHUNKS,Frac> as WideMul>::Output:Ord,
|
||||
{
|
||||
pub fn sqrt_unchecked(self)->Self{
|
||||
//pow2 must be the minimum power of two which when squared is greater than self
|
||||
//the algorithm:
|
||||
//1. count "used" bits to the left of the decimal
|
||||
//2. add one
|
||||
//This is the power of two which is greater than self.
|
||||
//3. divide by 2 via >>1
|
||||
//4. add on fractional offset
|
||||
//Voila
|
||||
//0001.0000 Fixed<u8,4>
|
||||
//sqrt
|
||||
//0110.0000
|
||||
//pow2 = 0100.0000
|
||||
let mut pow2=Self{
|
||||
bits:BInt::<CHUNKS>::ONE.shl(((((CHUNKS as i32*64-Frac::I32-(self.bits.leading_zeros() as i32)+1)>>1)+Frac::I32) as u32).saturating_sub(1)),
|
||||
frac:PhantomData,
|
||||
};
|
||||
let mut result=pow2;
|
||||
|
||||
//cheat to make the types match
|
||||
let wide_self=self.wide_mul(Fixed::<CHUNKS,Frac>::ONE);
|
||||
loop{
|
||||
//TODO: closed loop over bit shift exponent rather than pow2
|
||||
if pow2==Self::ZERO{
|
||||
break result;
|
||||
}
|
||||
//TODO: flip a single bit instead of adding a power of 2
|
||||
let new_result=result+pow2;
|
||||
//note that the implicit truncation in the multiply
|
||||
//means that the algorithm can return a result which squares to a number greater than the input.
|
||||
match wide_self.cmp(&new_result.wide_mul(new_result)){
|
||||
core::cmp::Ordering::Less=>(),
|
||||
core::cmp::Ordering::Equal=>break new_result,
|
||||
core::cmp::Ordering::Greater=>result=new_result,
|
||||
}
|
||||
pow2>>=1;
|
||||
}
|
||||
}
|
||||
pub fn sqrt(self)->Self{
|
||||
if self<Self::ZERO{
|
||||
panic!("Square root less than zero")
|
||||
}else{
|
||||
self.sqrt_unchecked()
|
||||
}
|
||||
}
|
||||
pub fn sqrt_checked(self)->Option<Self>{
|
||||
if self<Self::ZERO{
|
||||
None
|
||||
}else{
|
||||
Some(self.sqrt_unchecked())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,3 +9,6 @@ pub mod typenum{
|
||||
mod fixed_wide_traits;
|
||||
#[cfg(feature="fixed_wide_traits")]
|
||||
pub use ::fixed_wide_traits::wide;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
61
fixed_wide/src/tests.rs
Normal file
61
fixed_wide/src/tests.rs
Normal file
@@ -0,0 +1,61 @@
|
||||
use fixed_wide_traits::wide::WideMul;
|
||||
use crate::types::I32F32;
|
||||
|
||||
#[test]
|
||||
fn test_wide_mul(){
|
||||
let a=I32F32::ONE;
|
||||
let aa=a.wide_mul(a);
|
||||
assert_eq!(aa,crate::types::I64F64::ONE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bint(){
|
||||
let a=I32F32::ONE;
|
||||
assert_eq!(a*2,I32F32::from(2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sqrt(){
|
||||
let a=I32F32::ONE*4;
|
||||
assert_eq!(a.sqrt(),I32F32::from(2));
|
||||
}
|
||||
#[test]
|
||||
fn test_sqrt_low(){
|
||||
let a=I32F32::HALF;
|
||||
let b=a*a;
|
||||
assert_eq!(b.sqrt(),a);
|
||||
}
|
||||
fn find_equiv_sqrt_via_f64(n:I32F32)->I32F32{
|
||||
//GIMME THEM BITS BOY
|
||||
let &[bits]=n.to_bits().to_bits().digits();
|
||||
let ibits=bits as i64;
|
||||
let f=(ibits as f64)/((1u64<<32) as f64);
|
||||
let f_ans=f.sqrt();
|
||||
let i=(f_ans*((1u64<<32) as f64)) as i64;
|
||||
let r=I32F32::from_bits(bnum::BInt::<1>::from(i));
|
||||
//mimic the behaviour of the algorithm,
|
||||
//return the result if it truncates to the exact answer
|
||||
if (r+I32F32::EPSILON).wide_mul(r+I32F32::EPSILON)==n.wide_mul(I32F32::ONE){
|
||||
return r+I32F32::EPSILON;
|
||||
}
|
||||
if (r-I32F32::EPSILON).wide_mul(r-I32F32::EPSILON)==n.wide_mul(I32F32::ONE){
|
||||
return r-I32F32::EPSILON;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
fn test_exact(n:I32F32){
|
||||
assert_eq!(n.sqrt(),find_equiv_sqrt_via_f64(n));
|
||||
}
|
||||
#[test]
|
||||
fn test_sqrt_exact(){
|
||||
//43
|
||||
for i in 0..((i64::MAX as f32).ln() as u32){
|
||||
let n=I32F32::from_bits(bnum::BInt::<1>::from((i as f32).exp() as i64));
|
||||
test_exact(n);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn test_sqrt_max(){
|
||||
let a=I32F32::MAX;
|
||||
test_exact(a);
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
use std::ops::Add;
|
||||
use fixed_wide_traits::wide::WideDot;
|
||||
|
||||
//TODO: replace this with 4x3 matrix
|
||||
// mat4x3.wide_dot(vec3.extend(1))
|
||||
|
||||
pub struct Affine<M,T>{
|
||||
pub matrix:M,
|
||||
pub offset:T,
|
||||
pub matrix:M,
|
||||
pub offset:T,
|
||||
}
|
||||
|
||||
impl<M:Copy,T:Copy> Affine<M,T>{
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_length_operations {
|
||||
( $struct: ident { $($field: ident), + }, $size: expr ) => {
|
||||
impl<U,T:Copy+fixed_wide_traits::wide::WideMul<Output=U>> $struct<T> {
|
||||
type Output=$struct<U>;
|
||||
#[inline]
|
||||
fn wide_with_length(self, rhs: Self) -> Self::Output {
|
||||
let len=self.wide_length();
|
||||
let ratio=rhs.ratio(len);
|
||||
self.wide_mul(ratio)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,283 +1,291 @@
|
||||
#[cfg(feature="fixed_wide_traits")]
|
||||
pub mod wide;
|
||||
#[cfg(all(feature="fixed_wide_traits",feature="deferred_division"))]
|
||||
pub mod length;
|
||||
|
||||
// Stolen from https://github.com/c1m50c/fixed-vectors (MIT license)
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_vector {
|
||||
( $struct: ident { $($field: ident), + }, ( $($generic: ident), + ), $size: expr ) => {
|
||||
impl<T> $struct<T> {
|
||||
/// Constructs a new vector with the specified values for each field.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use fixed_wide_vectors::Vector2;
|
||||
///
|
||||
/// let vec2 = Vector2::new(0, 0);
|
||||
///
|
||||
/// assert_eq!(vec2.x, 0);
|
||||
/// assert_eq!(vec2.y, 0);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub const fn new( $($field: T), + ) -> Self {
|
||||
Self {
|
||||
$( $field ), +
|
||||
}
|
||||
}
|
||||
( $struct: ident { $($field: ident), + }, ( $($generic: ident), + ), $size: expr ) => {
|
||||
impl<T> $struct<T> {
|
||||
/// Constructs a new vector with the specified values for each field.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use fixed_wide_vectors::Vector2;
|
||||
///
|
||||
/// let vec2 = Vector2::new(0, 0);
|
||||
///
|
||||
/// assert_eq!(vec2.x, 0);
|
||||
/// assert_eq!(vec2.y, 0);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub const fn new( $($field: T), + ) -> Self {
|
||||
Self {
|
||||
$( $field ), +
|
||||
}
|
||||
}
|
||||
|
||||
/// Consumes the vector and returns its values as an array.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use fixed_wide_vectors::Vector2;
|
||||
///
|
||||
/// let vec2 = Vector2::new(0, 0);
|
||||
/// let array = vec2.to_array();
|
||||
///
|
||||
/// assert_eq!(array, [0, 0]);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn to_array(self) -> [T; $size] {
|
||||
[ $(self.$field), + ]
|
||||
}
|
||||
/// Consumes the vector and returns its values as an array.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use fixed_wide_vectors::Vector2;
|
||||
///
|
||||
/// let vec2 = Vector2::new(0, 0);
|
||||
/// let array = vec2.to_array();
|
||||
///
|
||||
/// assert_eq!(array, [0, 0]);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn to_array(self) -> [T; $size] {
|
||||
[ $(self.$field), + ]
|
||||
}
|
||||
|
||||
/// Consumes the vector and returns its values as a tuple.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use fixed_wide_vectors::Vector2;
|
||||
///
|
||||
/// let vec2 = Vector2::new(0, 0);
|
||||
/// let tuple = vec2.to_tuple();
|
||||
///
|
||||
/// assert_eq!(tuple, (0, 0));
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn to_tuple(self) -> ( $($generic), + ) {
|
||||
( $(self.$field), + )
|
||||
}
|
||||
/// Consumes the vector and returns its values as a tuple.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use fixed_wide_vectors::Vector2;
|
||||
///
|
||||
/// let vec2 = Vector2::new(0, 0);
|
||||
/// let tuple = vec2.to_tuple();
|
||||
///
|
||||
/// assert_eq!(tuple, (0, 0));
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn to_tuple(self) -> ( $($generic), + ) {
|
||||
( $(self.$field), + )
|
||||
}
|
||||
|
||||
/// Consumes the vector and returns a new vector with the given function applied on each field.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use fixed_wide_vectors::Vector2;
|
||||
///
|
||||
/// let vec2 = Vector2::new(1, 2)
|
||||
/// .map(|i| i * 2);
|
||||
///
|
||||
/// assert_eq!(vec2, Vector2::new(2, 4));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map<F, U>(self, f: F) -> $struct<U>
|
||||
where
|
||||
F: Fn(T) -> U
|
||||
{
|
||||
$struct {
|
||||
$( $field: f(self.$field) ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Consumes the vector and returns a new vector with the given function applied on each field.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use fixed_wide_vectors::Vector2;
|
||||
///
|
||||
/// let vec2 = Vector2::new(1, 2)
|
||||
/// .map(|i| i * 2);
|
||||
///
|
||||
/// assert_eq!(vec2, Vector2::new(2, 4));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn map<F, U>(self, f: F) -> $struct<U>
|
||||
where
|
||||
F: Fn(T) -> U
|
||||
{
|
||||
$struct {
|
||||
$( $field: f(self.$field) ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy> $struct<T> {
|
||||
/// Constructs a vector using the given `value` as the value for all of its fields.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use fixed_wide_vectors::Vector2;
|
||||
///
|
||||
/// let vec2 = Vector2::from_value(0);
|
||||
///
|
||||
/// assert_eq!(vec2, Vector2::new(0, 0));
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub const fn from_value(value: T) -> Self {
|
||||
Self {
|
||||
$( $field: value ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: Copy> $struct<T> {
|
||||
/// Constructs a vector using the given `value` as the value for all of its fields.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use fixed_wide_vectors::Vector2;
|
||||
///
|
||||
/// let vec2 = Vector2::from_value(0);
|
||||
///
|
||||
/// assert_eq!(vec2, Vector2::new(0, 0));
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub const fn from_value(value: T) -> Self {
|
||||
Self {
|
||||
$( $field: value ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<[T; $size]> for $struct<T> {
|
||||
fn from(from: [T; $size]) -> Self {
|
||||
let mut iterator = from.into_iter();
|
||||
impl<T> From<[T; $size]> for $struct<T> {
|
||||
fn from(from: [T; $size]) -> Self {
|
||||
let mut iterator = from.into_iter();
|
||||
|
||||
Self {
|
||||
// SAFETY: We know the size of `from` so `iterator.next()` is always `Some(..)`
|
||||
$( $field: unsafe { iterator.next().unwrap_unchecked() } ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
Self {
|
||||
// SAFETY: We know the size of `from` so `iterator.next()` is always `Some(..)`
|
||||
$( $field: unsafe { iterator.next().unwrap_unchecked() } ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<($($generic), +)> for $struct<T> {
|
||||
fn from(from: ($($generic), +)) -> Self {
|
||||
let ( $($field), + ) = from;
|
||||
impl<T> From<($($generic), +)> for $struct<T> {
|
||||
fn from(from: ($($generic), +)) -> Self {
|
||||
let ( $($field), + ) = from;
|
||||
|
||||
Self {
|
||||
$( $field ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
Self {
|
||||
$( $field ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: core::fmt::Debug> core::fmt::Debug for $struct<T> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
let identifier = core::stringify!($struct);
|
||||
impl<T: core::fmt::Debug> core::fmt::Debug for $struct<T> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
let identifier = core::stringify!($struct);
|
||||
|
||||
f.debug_struct(identifier)
|
||||
$( .field( core::stringify!($field), &self.$field ) ) +
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
f.debug_struct(identifier)
|
||||
$( .field( core::stringify!($field), &self.$field ) ) +
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq> PartialEq for $struct<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
$( self.$field == other.$field ) && +
|
||||
}
|
||||
}
|
||||
impl<T: PartialEq> PartialEq for $struct<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
$( self.$field == other.$field ) && +
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Eq> Eq for $struct<T> { }
|
||||
impl<T: Eq> Eq for $struct<T> { }
|
||||
|
||||
impl<T: core::hash::Hash> core::hash::Hash for $struct<T> {
|
||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
$( self.$field.hash(state); ) +
|
||||
}
|
||||
}
|
||||
impl<T: core::hash::Hash> core::hash::Hash for $struct<T> {
|
||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
$( self.$field.hash(state); ) +
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> Clone for $struct<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
$( $field: self.$field.clone() ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: Clone> Clone for $struct<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
$( $field: self.$field.clone() ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy> Copy for $struct<T> { }
|
||||
impl<T: Copy> Copy for $struct<T> { }
|
||||
|
||||
impl<T: Default> Default for $struct<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
$( $field: T::default() ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: Default> Default for $struct<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
$( $field: T::default() ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Ord> $struct<T> {
|
||||
pub fn min(self, rhs: Self) -> $struct<T> {
|
||||
$struct{
|
||||
$( $field: self.$field.min(rhs.$field) ), +
|
||||
}
|
||||
}
|
||||
pub fn max(self, rhs: Self) -> $struct<T> {
|
||||
$struct{
|
||||
$( $field: self.$field.max(rhs.$field) ), +
|
||||
}
|
||||
}
|
||||
pub fn cmp(self, rhs: Self) -> $struct<core::cmp::Ordering> {
|
||||
$struct{
|
||||
$( $field: self.$field.cmp(&rhs.$field) ), +
|
||||
}
|
||||
}
|
||||
pub fn lt(self, rhs: Self) -> $struct<bool> {
|
||||
$struct{
|
||||
$( $field: self.$field.lt(&rhs.$field) ), +
|
||||
}
|
||||
}
|
||||
pub fn gt(self, rhs: Self) -> $struct<bool> {
|
||||
$struct{
|
||||
$( $field: self.$field.gt(&rhs.$field) ), +
|
||||
}
|
||||
}
|
||||
pub fn ge(self, rhs: Self) -> $struct<bool> {
|
||||
$struct{
|
||||
$( $field: self.$field.ge(&rhs.$field) ), +
|
||||
}
|
||||
}
|
||||
pub fn le(self, rhs: Self) -> $struct<bool> {
|
||||
$struct{
|
||||
$( $field: self.$field.le(&rhs.$field) ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: Ord> $struct<T> {
|
||||
pub fn min(self, rhs: Self) -> $struct<T> {
|
||||
$struct{
|
||||
$( $field: self.$field.min(rhs.$field) ), +
|
||||
}
|
||||
}
|
||||
pub fn max(self, rhs: Self) -> $struct<T> {
|
||||
$struct{
|
||||
$( $field: self.$field.max(rhs.$field) ), +
|
||||
}
|
||||
}
|
||||
pub fn cmp(self, rhs: Self) -> $struct<core::cmp::Ordering> {
|
||||
$struct{
|
||||
$( $field: self.$field.cmp(&rhs.$field) ), +
|
||||
}
|
||||
}
|
||||
pub fn lt(self, rhs: Self) -> $struct<bool> {
|
||||
$struct{
|
||||
$( $field: self.$field.lt(&rhs.$field) ), +
|
||||
}
|
||||
}
|
||||
pub fn gt(self, rhs: Self) -> $struct<bool> {
|
||||
$struct{
|
||||
$( $field: self.$field.gt(&rhs.$field) ), +
|
||||
}
|
||||
}
|
||||
pub fn ge(self, rhs: Self) -> $struct<bool> {
|
||||
$struct{
|
||||
$( $field: self.$field.ge(&rhs.$field) ), +
|
||||
}
|
||||
}
|
||||
pub fn le(self, rhs: Self) -> $struct<bool> {
|
||||
$struct{
|
||||
$( $field: self.$field.le(&rhs.$field) ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: core::ops::Neg<Output = T>> core::ops::Neg for $struct<T> {
|
||||
type Output = Self;
|
||||
impl $struct<bool>{
|
||||
pub fn all(&self)->bool{
|
||||
const ALL:[bool;$size]=[true;$size];
|
||||
core::matches!(self.to_array(),ALL)
|
||||
}
|
||||
pub fn any(&self)->bool{
|
||||
$( self.$field )|| +
|
||||
}
|
||||
}
|
||||
|
||||
fn neg(self) -> Self::Output {
|
||||
Self {
|
||||
$( $field: -self.$field ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: core::ops::Neg<Output = T>> core::ops::Neg for $struct<T> {
|
||||
type Output = Self;
|
||||
|
||||
// Impl arithmetic pperators
|
||||
$crate::impl_operator!( $struct { $($field), + }, AddAssign, add_assign );
|
||||
$crate::impl_operator!( $struct { $($field), + }, Add, add, Self );
|
||||
$crate::impl_operator!( $struct { $($field), + }, SubAssign, sub_assign );
|
||||
$crate::impl_operator!( $struct { $($field), + }, Sub, sub, Self );
|
||||
$crate::impl_operator!( $struct { $($field), + }, MulAssign, mul_assign );
|
||||
$crate::impl_operator!( $struct { $($field), + }, Mul, mul, Self );
|
||||
$crate::impl_operator!( $struct { $($field), + }, DivAssign, div_assign );
|
||||
$crate::impl_operator!( $struct { $($field), + }, Div, div, Self );
|
||||
$crate::impl_operator!( $struct { $($field), + }, RemAssign, rem_assign );
|
||||
$crate::impl_operator!( $struct { $($field), + }, Rem, rem, Self );
|
||||
fn neg(self) -> Self::Output {
|
||||
Self {
|
||||
$( $field: -self.$field ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Impl bitwise operators
|
||||
$crate::impl_operator!( $struct { $($field), + }, BitAndAssign, bitand_assign );
|
||||
$crate::impl_operator!( $struct { $($field), + }, BitAnd, bitand, Self );
|
||||
$crate::impl_operator!( $struct { $($field), + }, BitOrAssign, bitor_assign );
|
||||
$crate::impl_operator!( $struct { $($field), + }, BitOr, bitor, Self );
|
||||
$crate::impl_operator!( $struct { $($field), + }, BitXorAssign, bitxor_assign );
|
||||
$crate::impl_operator!( $struct { $($field), + }, BitXor, bitxor, Self );
|
||||
// Impl arithmetic pperators
|
||||
$crate::impl_operator!( $struct { $($field), + }, AddAssign, add_assign );
|
||||
$crate::impl_operator!( $struct { $($field), + }, Add, add, Self );
|
||||
$crate::impl_operator!( $struct { $($field), + }, SubAssign, sub_assign );
|
||||
$crate::impl_operator!( $struct { $($field), + }, Sub, sub, Self );
|
||||
$crate::impl_operator!( $struct { $($field), + }, MulAssign, mul_assign );
|
||||
$crate::impl_operator!( $struct { $($field), + }, Mul, mul, Self );
|
||||
$crate::impl_operator!( $struct { $($field), + }, DivAssign, div_assign );
|
||||
$crate::impl_operator!( $struct { $($field), + }, Div, div, Self );
|
||||
$crate::impl_operator!( $struct { $($field), + }, RemAssign, rem_assign );
|
||||
$crate::impl_operator!( $struct { $($field), + }, Rem, rem, Self );
|
||||
|
||||
// Impl floating-point based methods
|
||||
$crate::impl_wide_operations!( $struct { $($field), + }, $size );
|
||||
};
|
||||
// Impl bitwise operators
|
||||
$crate::impl_operator!( $struct { $($field), + }, BitAndAssign, bitand_assign );
|
||||
$crate::impl_operator!( $struct { $($field), + }, BitAnd, bitand, Self );
|
||||
$crate::impl_operator!( $struct { $($field), + }, BitOrAssign, bitor_assign );
|
||||
$crate::impl_operator!( $struct { $($field), + }, BitOr, bitor, Self );
|
||||
$crate::impl_operator!( $struct { $($field), + }, BitXorAssign, bitxor_assign );
|
||||
$crate::impl_operator!( $struct { $($field), + }, BitXor, bitxor, Self );
|
||||
|
||||
// Impl floating-point based methods
|
||||
#[cfg(feature="fixed_wide_traits")]
|
||||
$crate::impl_wide_operations!( $struct { $($field), + }, $size );
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_operator {
|
||||
( $struct: ident { $($field: ident), + }, $trait: ident, $method: ident, $output: ty ) => {
|
||||
impl<T: core::ops::$trait<Output = T>> core::ops::$trait<Self> for $struct<T> {
|
||||
type Output = $output;
|
||||
( $struct: ident { $($field: ident), + }, $trait: ident, $method: ident, $output: ty ) => {
|
||||
impl<T:core::ops::$trait<Output=T>> core::ops::$trait for $struct<T> {
|
||||
type Output = $output;
|
||||
|
||||
fn $method(self, other: Self) -> Self::Output {
|
||||
Self {
|
||||
$( $field: self.$field.$method(other.$field) ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
fn $method(self, other: Self) -> Self::Output {
|
||||
Self {
|
||||
$( $field: self.$field.$method(other.$field) ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T:core::ops::$trait<Output=T>+Copy> core::ops::$trait<T> for $struct<T>{
|
||||
type Output = $output;
|
||||
|
||||
impl<T: core::ops::$trait<Output = T> + Copy> core::ops::$trait<T> for $struct<T> {
|
||||
type Output = $output;
|
||||
fn $method(self, other: T) -> Self::Output {
|
||||
$struct {
|
||||
$( $field: self.$field.$method(other) ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fn $method(self, other: T) -> Self::Output {
|
||||
Self {
|
||||
$( $field: self.$field.$method(other) ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
( $struct: ident { $($field: ident), + }, $trait: ident, $method: ident ) => {
|
||||
impl<T: core::ops::$trait> core::ops::$trait for $struct<T> {
|
||||
fn $method(&mut self, other: Self) {
|
||||
$( self.$field.$method(other.$field) ); +
|
||||
}
|
||||
}
|
||||
|
||||
( $struct: ident { $($field: ident), + }, $trait: ident, $method: ident ) => {
|
||||
impl<T: core::ops::$trait> core::ops::$trait for $struct<T> {
|
||||
fn $method(&mut self, other: Self) {
|
||||
$( self.$field.$method(other.$field) ); +
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: core::ops::$trait + Copy> core::ops::$trait<T> for $struct<T> {
|
||||
fn $method(&mut self, other: T) {
|
||||
$( self.$field.$method(other) ); +
|
||||
}
|
||||
}
|
||||
};
|
||||
impl<T: core::ops::$trait + Copy> core::ops::$trait<T> for $struct<T> {
|
||||
fn $method(&mut self, other: T) {
|
||||
$( self.$field.$method(other) ); +
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_wide_operations {
|
||||
( $struct: ident { $($field: ident), + }, $size: expr ) => {
|
||||
impl<U,T:Copy+fixed_wide_traits::wide::WideMul<Output=U>> fixed_wide_traits::wide::WideMul for $struct<T> {
|
||||
( $struct: ident { $($field: ident), + }, $size: expr ) => {
|
||||
impl<U,T:Copy+fixed_wide_traits::wide::WideMul<Output=U>> fixed_wide_traits::wide::WideMul for $struct<T> {
|
||||
type Output=$struct<U>;
|
||||
#[inline]
|
||||
fn wide_mul(self, rhs: Self) -> Self::Output {
|
||||
$struct{
|
||||
$( $field: self.$field.wide_mul(rhs.$field) ), +
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
fn wide_mul(self, rhs: Self) -> Self::Output {
|
||||
$struct{
|
||||
$( $field: self.$field.wide_mul(rhs.$field) ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<U:std::ops::Add<Output=U>,T:Copy+fixed_wide_traits::wide::WideMul<Output=U>> $struct<T> {
|
||||
#[inline]
|
||||
pub fn wide_dot(self, other: Self) -> U {
|
||||
$crate::sum_repeating!(
|
||||
$( + (self.$field.wide_mul(other.$field)) ) +
|
||||
)
|
||||
}
|
||||
pub fn wide_length_squared(&self) -> U {
|
||||
let squared = $struct {
|
||||
$( $field: self.$field.wide_mul(self.$field) ), +
|
||||
};
|
||||
|
||||
$crate::sum_repeating!(
|
||||
$( + squared.$field ) +
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
impl<V:core::ops::Add<Output=V>,U,T:fixed_wide_traits::wide::WideMul<U,Output=V>> fixed_wide_traits::wide::WideDot<$struct<U>> for $struct<T> {
|
||||
type Output=V;
|
||||
#[inline]
|
||||
fn wide_dot(self, rhs: $struct<U>) -> Self::Output {
|
||||
$crate::sum_repeating!(
|
||||
$( + (self.$field.wide_mul(rhs.$field)) ) +
|
||||
)
|
||||
}
|
||||
}
|
||||
impl<U:std::ops::Add<Output=U>,T:Copy+fixed_wide_traits::wide::WideMul<Output=U>> $struct<T> {
|
||||
#[inline]
|
||||
pub fn wide_length_squared(&self) -> U {
|
||||
$crate::sum_repeating!(
|
||||
$( + self.$field.wide_mul(self.$field) ) +
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ macro_rules! impl_wide_operations {
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! sum_repeating {
|
||||
( + $($item: tt) * ) => {
|
||||
$($item) *
|
||||
};
|
||||
( + $($item: tt) * ) => {
|
||||
$($item) *
|
||||
};
|
||||
}
|
||||
|
||||
51
fixed_wide_vectors/src/tests/fixed_wide_traits.rs
Normal file
51
fixed_wide_vectors/src/tests/fixed_wide_traits.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use fixed_wide_traits::wide::WideMul;
|
||||
use fixed_wide_traits::wide::WideDot;
|
||||
|
||||
use crate::Vector3;
|
||||
|
||||
type Planar64=fixed_wide::types::I32F32;
|
||||
//type Planar64Wide1=fixed::types::I64F64;
|
||||
//type Planar64Wide2=fixed_wide::types::I128F128;
|
||||
type Planar64Wide3=fixed_wide::types::I256F256;
|
||||
|
||||
#[test]
|
||||
fn wide_int64() {
|
||||
let a=Planar64::from(2);
|
||||
let b=Planar64::from(3);
|
||||
|
||||
let w1=a.wide_mul(b);
|
||||
let w2=w1.wide_mul(w1);
|
||||
let w3=w2.wide_mul(w2);
|
||||
|
||||
assert_eq!(w3,Planar64Wide3::from((3i128*2).pow(4)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wide_vec3(){
|
||||
let v=Vector3::from_value(Planar64::from(3));
|
||||
let v1=v.wide_mul(v);
|
||||
let v2=v1.wide_mul(v1);
|
||||
let v3=v2.wide_mul(v2);
|
||||
|
||||
assert_eq!(v3,Vector3::from_value(Planar64Wide3::from(3i128.pow(8))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wide_vec3_dot(){
|
||||
let v=Vector3::from_value(Planar64::from(3));
|
||||
let v1=v.wide_mul(v);
|
||||
let v2=v1.wide_mul(v1);
|
||||
let v3=v2.wide_dot(v2);
|
||||
|
||||
assert_eq!(v3,Planar64Wide3::from(3i128.pow(8)*3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wide_vec3_length_squared(){
|
||||
let v=Vector3::from_value(Planar64::from(3));
|
||||
let v1=v.wide_mul(v);
|
||||
let v2=v1.wide_mul(v1);
|
||||
let v3=v2.wide_length_squared();
|
||||
|
||||
assert_eq!(v3,Planar64Wide3::from(3i128.pow(8)*3));
|
||||
}
|
||||
@@ -1,62 +1,5 @@
|
||||
use fixed_wide_traits::wide::WideMul;
|
||||
mod tests;
|
||||
|
||||
use crate::Vector3;
|
||||
|
||||
type Planar64=fixed_wide::types::I32F32;
|
||||
//type Planar64Wide1=fixed::types::I64F64;
|
||||
//type Planar64Wide2=fixed_wide::types::I128F128;
|
||||
type Planar64Wide3=fixed_wide::types::I256F256;
|
||||
|
||||
#[test]
|
||||
fn wide_int64() {
|
||||
let a=Planar64::from(2);
|
||||
let b=Planar64::from(3);
|
||||
|
||||
let w1=a.wide_mul(b);
|
||||
let w2=w1.wide_mul(w1);
|
||||
let w3=w2.wide_mul(w2);
|
||||
|
||||
assert_eq!(w3,Planar64Wide3::from((3i128*2).pow(4)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn you_can_add_numbers(){
|
||||
let a=Planar64Wide3::from((3i128*2).pow(4));
|
||||
assert_eq!(a+a,Planar64Wide3::from((3i128*2).pow(4)*2))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn you_can_shr_numbers(){
|
||||
let a=Planar64::from(4);
|
||||
assert_eq!(a>>1,Planar64::from(2))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wide_vec3(){
|
||||
let v=Vector3::from_value(Planar64::from(3));
|
||||
let v1=v.wide_mul(v);
|
||||
let v2=v1.wide_mul(v1);
|
||||
let v3=v2.wide_mul(v2);
|
||||
|
||||
assert_eq!(v3,Vector3::from_value(Planar64Wide3::from(3i128.pow(8))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wide_vec3_dot(){
|
||||
let v=Vector3::from_value(Planar64::from(3));
|
||||
let v1=v.wide_mul(v);
|
||||
let v2=v1.wide_mul(v1);
|
||||
let v3=v2.wide_dot(v2);
|
||||
|
||||
assert_eq!(v3,Planar64Wide3::from(3i128.pow(8)*3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wide_vec3_length_squared(){
|
||||
let v=Vector3::from_value(Planar64::from(3));
|
||||
let v1=v.wide_mul(v);
|
||||
let v2=v1.wide_mul(v1);
|
||||
let v3=v2.wide_length_squared();
|
||||
|
||||
assert_eq!(v3,Planar64Wide3::from(3i128.pow(8)*3));
|
||||
}
|
||||
#[cfg(feature="fixed_wide_traits")]
|
||||
mod fixed_wide_traits;
|
||||
|
||||
16
fixed_wide_vectors/src/tests/tests.rs
Normal file
16
fixed_wide_vectors/src/tests/tests.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
type Planar64=fixed_wide::types::I32F32;
|
||||
//type Planar64Wide1=fixed::types::I64F64;
|
||||
//type Planar64Wide2=fixed_wide::types::I128F128;
|
||||
type Planar64Wide3=fixed_wide::types::I256F256;
|
||||
|
||||
#[test]
|
||||
fn you_can_add_numbers(){
|
||||
let a=Planar64Wide3::from((3i128*2).pow(4));
|
||||
assert_eq!(a+a,Planar64Wide3::from((3i128*2).pow(4)*2))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn you_can_shr_numbers(){
|
||||
let a=Planar64::from(4);
|
||||
assert_eq!(a>>1,Planar64::from(2))
|
||||
}
|
||||
@@ -14,8 +14,8 @@
|
||||
/// assert_eq!(vec2.y, 4);
|
||||
/// ```
|
||||
pub struct Vector2<T> {
|
||||
pub x: T,
|
||||
pub y: T,
|
||||
pub x: T,
|
||||
pub y: T,
|
||||
}
|
||||
|
||||
|
||||
@@ -34,9 +34,9 @@ pub struct Vector2<T> {
|
||||
/// assert_eq!(vec3.z, 6);
|
||||
/// ```
|
||||
pub struct Vector3<T> {
|
||||
pub x: T,
|
||||
pub y: T,
|
||||
pub z: T,
|
||||
pub x: T,
|
||||
pub y: T,
|
||||
pub z: T,
|
||||
}
|
||||
|
||||
|
||||
@@ -56,10 +56,10 @@ pub struct Vector3<T> {
|
||||
/// assert_eq!(vec4.w, 8);
|
||||
/// ```
|
||||
pub struct Vector4<T> {
|
||||
pub x: T,
|
||||
pub y: T,
|
||||
pub z: T,
|
||||
pub w: T,
|
||||
pub x: T,
|
||||
pub y: T,
|
||||
pub z: T,
|
||||
pub w: T,
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user