28 Commits

Author SHA1 Message Date
c51dc6098c matrix: directly implement dot product to avoid a copy 2024-09-04 12:04:08 -07:00
6aba246453 umm the macro 2024-09-04 12:04:08 -07:00
f7ae745bef probably wrong stuff 2024-09-03 12:53:42 -07:00
1f1568ebe9 wip mat mul 2024-09-03 12:53:42 -07:00
176eb762e3 name macros better 2024-09-03 12:51:19 -07:00
15bd78c0e1 matrix wide dot test 2024-09-03 10:59:47 -07:00
0f9d0c8c39 matrix wide dot 2024-09-03 10:59:18 -07:00
eefbdafc16 move more impls to common 2024-09-03 10:40:43 -07:00
b0ecfeb294 the matrix super macro 2024-09-03 10:10:46 -07:00
48a8271b99 transpose macro_repeated 2024-09-03 10:10:30 -07:00
1604888254 macro macro 2024-09-03 10:01:22 -07:00
4017f33447 delete comment 2024-09-03 09:40:49 -07:00
f0527714db move macro to mod 2024-09-03 09:40:46 -07:00
27d96f9b19 delete tuple impls 2024-09-03 09:30:13 -07:00
a5094fe873 common impls between matrix and vector 2024-09-02 18:54:50 -07:00
1bd45283a9 delete unused test 2024-09-02 18:36:05 -07:00
a6dc0c37ba MACRO MACRO MACRO 2024-09-02 18:35:37 -07:00
83434a89c7 wide_dot 2024-09-02 18:25:21 -07:00
b14c84bdad MACRO MACRO MACRO 2024-09-02 18:19:35 -07:00
e98744871b narrow paste scope 2024-09-02 18:19:35 -07:00
c26ce93fc8 paste 2024-09-02 18:19:35 -07:00
c856509759 remove old comment 2024-09-02 18:19:35 -07:00
5cb98ee29f vectors: no traits 2024-09-02 18:19:35 -07:00
bc29cd9848 move tests 2024-09-02 17:44:04 -07:00
502ab7f33f named function 2024-09-02 17:09:37 -07:00
e0dba8840e ruin everything successfully 2024-09-02 17:03:01 -07:00
4d13b4ada7 paste (this sucks) 2024-09-02 16:35:01 -07:00
2a2e729f59 wip 2024-09-02 16:15:17 -07:00
38 changed files with 857 additions and 983 deletions

@ -1 +0,0 @@
/target

@ -1,36 +0,0 @@
# This file is automatically @generated by Cargo.
# 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"

@ -1,14 +0,0 @@
[package]
name = "deferred_division"
version = "0.1.0"
edition = "2021"
[features]
default=["fixed_wide_traits"]
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,8 +0,0 @@
pub mod ratio;
#[cfg(feature="fixed_wide_traits")]
mod wide;
#[cfg(test)]
mod tests;

@ -1,157 +0,0 @@
use std::ops::Mul;
#[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}
}
}
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,
}
}
}
};
}
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);
}
}

@ -1,4 +0,0 @@
mod tests;
#[cfg(feature="fixed_wide_traits")]
mod wide;

@ -1,22 +0,0 @@
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);
}

@ -1,15 +0,0 @@
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,58 +0,0 @@
use std::ops::{Add,Mul};
use crate::ratio::Ratio;
use fixed_wide_traits::wide::{WideMul,WideDiv,WideDot,WideCross};
impl<Num,Den:Copy> Ratio<Num,Den>
{
pub fn rational_add<T>(self,rhs:T)->Ratio<<Num as Add<<Den as Mul<T>>::Output>>::Output,Den>
where
Den:Mul<T>,
Num:Add<<Den as Mul<T>>::Output>,
{
Ratio{
num:self.num+self.den.mul(rhs),
den:self.den,
}
}
pub fn wide_rational_add<T>(self,rhs:T)->Ratio<<Num as Add<<Den as WideMul<T>>::Output>>::Output,Den>
where
Den:WideMul<T>,
Num:Add<<Den as WideMul<T>>::Output>,
{
Ratio{
num:self.num+self.den.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>,
{
type Output=Ratio<Num,<Den as WideMul<T>>::Output>;
fn wide_div(self,rhs:T)->Ratio<Num,<Den as WideMul<T>>::Output>{
Ratio{
num:self.num,
den:self.den.wide_mul(rhs),
}
}
}

20
fixed_wide/Cargo.lock generated

@ -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,17 +18,13 @@ checksum = "3e31ea183f6ee62ac8b8a8cf7feddd766317adfb13ff469de57ce033efd6a790"
name = "fixed_wide"
version = "0.1.0"
dependencies = [
"arrayvec",
"bnum",
"fixed_wide_traits",
"typenum",
"paste",
]
[[package]]
name = "fixed_wide_traits"
version = "0.1.0"
[[package]]
name = "typenum"
version = "1.17.0"
name = "paste"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"

@ -4,10 +4,11 @@ version = "0.1.0"
edition = "2021"
[features]
default=["fixed_wide_traits"]
fixed_wide_traits=["dep:fixed_wide_traits"]
default=["zeroes"]
ratio=[]
zeroes=["ratio","dep:arrayvec"]
[dependencies]
bnum = "0.11.0"
typenum = "1.17.0"
fixed_wide_traits = { version = "0.1.0", path = "../fixed_wide_traits", optional = true }
arrayvec = { version = "0.7.6", optional = true }
paste = "1.0.15"

@ -1,35 +1,34 @@
use bnum::{BInt,cast::As};
use typenum::Unsigned;
#[derive(Clone,Copy,Debug,Hash)]
pub struct Fixed<const CHUNKS:usize,Frac>{
pub(crate)bits:BInt<{CHUNKS}>,
pub(crate)frac:std::marker::PhantomData<Frac>,
/// N is the number of u64s to use
/// F is the number of fractional bits (always N*32 lol)
pub struct Fixed<const N:usize,const F:usize>{
pub(crate)bits:BInt<{N}>,
}
impl<const CHUNKS:usize,Frac:Unsigned> Fixed<CHUNKS,Frac>{
pub const MAX:Self=Self::from_bits(BInt::<CHUNKS>::MAX);
pub const MIN:Self=Self::from_bits(BInt::<CHUNKS>::MIN);
pub const ZERO:Self=Self::from_bits(BInt::<CHUNKS>::ZERO);
pub const EPSILON:Self=Self::from_bits(BInt::<CHUNKS>::ONE);
pub const NEG_EPSILON:Self=Self::from_bits(BInt::<CHUNKS>::NEG_ONE);
pub const ONE:Self=Self::from_bits(BInt::<CHUNKS>::ONE.shl(Frac::U32));
pub const TWO:Self=Self::from_bits(BInt::<CHUNKS>::TWO.shl(Frac::U32));
pub const HALF:Self=Self::from_bits(BInt::<CHUNKS>::ONE.shl(Frac::U32-1));
pub const NEG_ONE:Self=Self::from_bits(BInt::<CHUNKS>::NEG_ONE.shl(Frac::U32));
pub const NEG_TWO:Self=Self::from_bits(BInt::<CHUNKS>::NEG_TWO.shl(Frac::U32));
pub const NEG_HALF:Self=Self::from_bits(BInt::<CHUNKS>::NEG_ONE.shl(Frac::U32-1));
impl<const N:usize,const F:usize> Fixed<N,F>{
pub const MAX:Self=Self::from_bits(BInt::<N>::MAX);
pub const MIN:Self=Self::from_bits(BInt::<N>::MIN);
pub const ZERO:Self=Self::from_bits(BInt::<N>::ZERO);
pub const EPSILON:Self=Self::from_bits(BInt::<N>::ONE);
pub const NEG_EPSILON:Self=Self::from_bits(BInt::<N>::NEG_ONE);
pub const ONE:Self=Self::from_bits(BInt::<N>::ONE.shl(F as u32));
pub const TWO:Self=Self::from_bits(BInt::<N>::TWO.shl(F as u32));
pub const HALF:Self=Self::from_bits(BInt::<N>::ONE.shl(F as u32-1));
pub const NEG_ONE:Self=Self::from_bits(BInt::<N>::NEG_ONE.shl(F as u32));
pub const NEG_TWO:Self=Self::from_bits(BInt::<N>::NEG_TWO.shl(F as u32));
pub const NEG_HALF:Self=Self::from_bits(BInt::<N>::NEG_ONE.shl(F as u32-1));
}
impl<const CHUNKS:usize,Frac> Fixed<CHUNKS,Frac>{
impl<const N:usize,const F:usize> Fixed<N,F>{
#[inline]
pub const fn from_bits(bits:BInt::<CHUNKS>)->Self{
pub const fn from_bits(bits:BInt::<N>)->Self{
Self{
bits,
frac:std::marker::PhantomData,
}
}
#[inline]
pub const fn to_bits(self)->BInt<CHUNKS>{
pub const fn to_bits(self)->BInt<N>{
self.bits
}
#[inline]
@ -38,34 +37,34 @@ impl<const CHUNKS:usize,Frac> Fixed<CHUNKS,Frac>{
}
}
impl<const CHUNKS:usize,Frac:Unsigned,T> From<T> for Fixed<CHUNKS,Frac>
impl<const N:usize,const F:usize,T> From<T> for Fixed<N,F>
where
BInt<CHUNKS>:From<T>
BInt<N>:From<T>
{
fn from(value:T)->Self{
Self::from_bits(BInt::<{CHUNKS}>::from(value)<<Frac::U32)
Self::from_bits(BInt::<{N}>::from(value)<<F as u32)
}
}
impl<const CHUNKS:usize,Frac> PartialEq for Fixed<CHUNKS,Frac>{
impl<const N:usize,const F:usize> PartialEq for Fixed<N,F>{
fn eq(&self,other:&Self)->bool{
self.bits.eq(&other.bits)
}
}
impl<const CHUNKS:usize,Frac> Eq for Fixed<CHUNKS,Frac>{}
impl<const N:usize,const F:usize> Eq for Fixed<N,F>{}
impl<const CHUNKS:usize,Frac> PartialOrd for Fixed<CHUNKS,Frac>{
impl<const N:usize,const F:usize> PartialOrd for Fixed<N,F>{
fn partial_cmp(&self,other:&Self)->Option<std::cmp::Ordering>{
self.bits.partial_cmp(&other.bits)
}
}
impl<const CHUNKS:usize,Frac> Ord for Fixed<CHUNKS,Frac>{
impl<const N:usize,const F:usize> Ord for Fixed<N,F>{
fn cmp(&self,other:&Self)->std::cmp::Ordering{
self.bits.cmp(&other.bits)
}
}
impl<const CHUNKS:usize,Frac> std::ops::Neg for Fixed<CHUNKS,Frac>{
impl<const N:usize,const F:usize> std::ops::Neg for Fixed<N,F>{
type Output=Self;
fn neg(self)->Self{
Self::from_bits(self.bits.neg())
@ -74,38 +73,38 @@ impl<const CHUNKS:usize,Frac> std::ops::Neg for Fixed<CHUNKS,Frac>{
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>{
impl<const N:usize,const F:usize> core::ops::$trait for $struct<N,F>{
type Output = $output;
fn $method(self, other: Self) -> Self::Output {
Self::from_bits(self.bits.$method(other.bits))
}
}
impl<const CHUNKS:usize,Frac:Unsigned,U> core::ops::$trait<U> for $struct<CHUNKS,Frac>
impl<const N:usize,const F:usize,U> core::ops::$trait<U> for $struct<N,F>
where
BInt::<CHUNKS>:From<U>,
BInt::<N>:From<U>,
{
type Output = $output;
fn $method(self, other: U) -> Self::Output {
Self::from_bits(self.bits.$method(BInt::<CHUNKS>::from(other)<<Frac::U32))
Self::from_bits(self.bits.$method(BInt::<N>::from(other).shl(F as u32)))
}
}
};
}
macro_rules! impl_additive_assign_operator {
( $struct: ident, $trait: ident, $method: ident ) => {
impl<const CHUNKS:usize,Frac> core::ops::$trait for $struct<CHUNKS,Frac>{
impl<const N:usize,const F:usize> core::ops::$trait for $struct<N,F>{
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>
impl<const N:usize,const F:usize,U> core::ops::$trait<U> for $struct<N,F>
where
BInt::<CHUNKS>:From<U>,
BInt::<N>:From<U>,
{
fn $method(&mut self, other: U) {
self.bits.$method(BInt::<CHUNKS>::from(other)<<Frac::U32);
self.bits.$method(BInt::<N>::from(other)<<F as u32);
}
}
};
@ -129,21 +128,21 @@ 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>{
impl<const F:usize> core::ops::$trait for $struct<$width,F>{
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::from_bits(lhs.mul(rhs).shr(Frac::U32).as_())
Self::from_bits(lhs.mul(rhs).shr(F as u32).as_())
}
}
};
}
macro_rules! impl_multiply_assign_operator_const {
( $width:expr, $struct: ident, $trait: ident, $method: ident ) => {
impl<Frac> core::ops::$trait for $struct<$width,Frac>{
impl<const F:usize> core::ops::$trait for $struct<$width,F>{
fn $method(&mut self, other: Self) {
self.bits.$method(other.bits);
}
@ -153,13 +152,13 @@ macro_rules! impl_multiply_assign_operator_const {
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>{
impl<const F:usize> core::ops::$trait for $struct<$width,F>{
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);
//this only needs to be $width+F as u32/64+1 but MUH CONST GENERICS!!!!!
let lhs=self.bits.as_::<BInt::<{$width*2}>>().shl(F as u32);
let rhs=other.bits.as_::<BInt::<{$width*2}>>();
Self::from_bits(lhs.div(rhs).as_())
}
@ -168,7 +167,7 @@ macro_rules! impl_divide_operator_const {
}
macro_rules! impl_divide_assign_operator_const {
( $width:expr, $struct: ident, $trait: ident, $method: ident ) => {
impl<Frac> core::ops::$trait for $struct<$width,Frac>{
impl<const F:usize> core::ops::$trait for $struct<$width,F>{
fn $method(&mut self, other: Self) {
self.bits.$method(other.bits);
}
@ -178,26 +177,26 @@ macro_rules! impl_divide_assign_operator_const {
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>
impl<const N:usize,const F:usize,U> core::ops::$trait<U> for $struct<N,F>
where
BInt::<CHUNKS>:From<U>+core::ops::$trait,
BInt::<N>:From<U>+core::ops::$trait,
{
type Output = $output;
fn $method(self, other: U) -> Self::Output {
Self::from_bits(self.bits.$method(BInt::<CHUNKS>::from(other)))
Self::from_bits(self.bits.$method(BInt::<N>::from(other)))
}
}
};
}
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>
impl<const N:usize,const F:usize,U> core::ops::$trait<U> for $struct<N,F>
where
BInt::<CHUNKS>:From<U>+core::ops::$trait,
BInt::<N>:From<U>+core::ops::$trait,
{
fn $method(&mut self, other: U) {
self.bits.$method(BInt::<CHUNKS>::from(other));
self.bits.$method(BInt::<N>::from(other));
}
}
};
@ -255,7 +254,7 @@ 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>{
impl<const N:usize,const F:usize> core::ops::$trait<u32> for $struct<N,F>{
type Output = $output;
fn $method(self, other: u32) -> Self::Output {
@ -266,7 +265,7 @@ macro_rules! impl_shift_operator {
}
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>{
impl<const N:usize,const F:usize> core::ops::$trait<u32> for $struct<N,F>{
fn $method(&mut self, other: u32) {
self.bits.$method(other);
}
@ -277,3 +276,102 @@ impl_shift_assign_operator!( Fixed, ShlAssign, shl_assign );
impl_shift_operator!( Fixed, Shl, shl, Self );
impl_shift_assign_operator!( Fixed, ShrAssign, shr_assign );
impl_shift_operator!( Fixed, Shr, shr, Self );
// WIDE MUL: multiply into a wider type
// let a = I32F32::ONE;
// let b:I64F64 = a.wide_mul(a);
macro_rules! impl_wide_mul{
($lhs:expr,$rhs:expr)=>{
impl Fixed<$lhs,{$lhs*32}>
{
paste::item!{
pub fn [<wide_mul_ $lhs _ $rhs>](self,rhs:Fixed<$rhs,{$rhs*32}>)->Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>{
Fixed::from_bits(self.bits.as_::<BInt<{$lhs+$rhs}>>()*rhs.bits.as_::<BInt<{$lhs+$rhs}>>())
}
}
}
};
}
macro_rules! impl_wide_mul_all{
($(($x:expr, $y:expr)),*)=>{
$(
impl_wide_mul!($x, $y);
)*
};
}
//const generics sidestepped wahoo
impl_wide_mul_all!(
(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)
);
impl<const SRC:usize,const F:usize> Fixed<SRC,F>{
pub fn resize_into<const DST:usize>(self)->Fixed<DST,F>{
Fixed::from_bits(self.bits.as_::<BInt<DST>>())
}
}
macro_rules! impl_const{
($n:expr)=>{
impl Fixed<{$n*2},{$n*2*32}>{
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!{
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:
//1. count "used" bits to the left of the decimal, not including the sign bit (so -1)
//2. divide by 2 via >>1 (sqrt-ish)
//3. add on fractional offset
//Voila
let used_bits=self.bits.bits() as i32-1-($n*32) as i32;
let max_shift=((used_bits>>1)+($n*32) as i32) as u32;
let mut result=Self::ZERO;
//multiply by one to make the types match (hack)
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.[<wide_mul_ $n _ $n>](new_result)<=wide_self{
result=new_result;
}
}
result
}
}
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())
}
}
}
}
}
impl_const!(1);
impl_const!(2);
impl_const!(3);
impl_const!(4);
impl_const!(5);
impl_const!(6);
impl_const!(7);
impl_const!(8);

@ -1,88 +0,0 @@
use bnum::BInt;
use bnum::cast::As;
use typenum::{Sum,Unsigned};
use crate::fixed::Fixed;
use fixed_wide_traits::wide::WideMul;
macro_rules! impl_wide_mul {
($lhs: expr,$rhs: expr) => {
impl<A,B> WideMul<Fixed<$rhs,B>> for Fixed<$lhs,A>
where
A:std::ops::Add<B>,
B:Unsigned,
{
type Output=Fixed<{$lhs+$rhs},Sum<A,B>>;
fn wide_mul(self,rhs:Fixed<$rhs,B>)->Self::Output{
Fixed::from_bits(self.bits.as_::<BInt<{$lhs+$rhs}>>()*rhs.bits.as_::<BInt<{$lhs+$rhs}>>())
}
}
};
}
macro_rules! impl_wide_mul_all {
($(($x:expr, $y:expr)),*) => {
$(
impl_wide_mul!($x, $y);
)*
};
}
//const generics sidestepped wahoo
impl_wide_mul_all!(
(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)
);
impl<const SRC:usize,Frac> Fixed<SRC,Frac>{
pub fn widen<const DST:usize>(self)->Fixed<DST,Frac>{
Fixed::from_bits(self.bits.as_::<BInt<DST>>())
}
}
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{
//1<<max_shift must be the minimum power of two which when squared is greater than self
//calculating max_shift:
//1. count "used" bits to the left of the decimal, not including the sign bit (so -1)
//2. divide by 2 via >>1 (sqrt-ish)
//3. add on fractional offset
//Voila
let used_bits=self.bits.bits() as i32-1-Frac::I32;
let max_shift=((used_bits>>1)+Frac::I32) as u32;
let mut result=Self::ZERO;
//multiply by one to make the types match (hack)
let wide_self=self.wide_mul(Fixed::<CHUNKS,Frac>::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|Fixed::<CHUNKS,Frac>::from_bits(BInt::from_bits(bnum::BUint::power_of_two(shift)));
if new_result.wide_mul(new_result)<=wide_self{
result=new_result;
}
}
result
}
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())
}
}
}

@ -1,14 +1,10 @@
pub mod fixed;
pub mod types;
pub mod typenum{
pub use typenum::Unsigned;
}
#[cfg(feature="fixed_wide_traits")]
mod fixed_wide_traits;
#[cfg(feature="fixed_wide_traits")]
pub use ::fixed_wide_traits::wide;
#[cfg(feature="zeroes")]
pub mod zeroes;
#[cfg(feature="ratio")]
pub mod ratio;
#[cfg(test)]
mod tests;

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,13 +1,37 @@
use fixed_wide_traits::wide::WideMul;
use crate::types::I32F32;
use crate::types::I256F256;
#[test]
fn you_can_add_numbers(){
let a=I256F256::from((3i128*2).pow(4));
assert_eq!(a+a,I256F256::from((3i128*2).pow(4)*2))
}
#[test]
fn you_can_shr_numbers(){
let a=I32F32::from(4);
assert_eq!(a>>1,I32F32::from(2))
}
#[test]
fn test_wide_mul(){
let a=I32F32::ONE;
let aa=a.wide_mul(a);
let aa=a.wide_mul_1_1(a);
assert_eq!(aa,crate::types::I64F64::ONE);
}
#[test]
fn test_wide_mul_repeated() {
let a=I32F32::from(2);
let b=I32F32::from(3);
let w1=a.wide_mul_1_1(b);
let w2=w1.wide_mul_2_2(w1);
let w3=w2.wide_mul_4_4(w2);
assert_eq!(w3,I256F256::from((3i128*2).pow(4)));
}
#[test]
fn test_bint(){
let a=I32F32::ONE;
@ -40,10 +64,10 @@ fn find_equiv_sqrt_via_f64(n:I32F32)->I32F32{
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){
if (r+I32F32::EPSILON).wide_mul_1_1(r+I32F32::EPSILON)==n.wide_mul_1_1(I32F32::ONE){
return r+I32F32::EPSILON;
}
if (r-I32F32::EPSILON).wide_mul(r-I32F32::EPSILON)==n.wide_mul(I32F32::ONE){
if (r-I32F32::EPSILON).wide_mul_1_1(r-I32F32::EPSILON)==n.wide_mul_1_1(I32F32::ONE){
return r-I32F32::EPSILON;
}
return r;

@ -1,4 +1,4 @@
pub type I32F32=crate::fixed::Fixed<1,typenum::consts::U32>;
pub type I64F64=crate::fixed::Fixed<2,typenum::consts::U64>;
pub type I128F128=crate::fixed::Fixed<4,typenum::consts::U128>;
pub type I256F256=crate::fixed::Fixed<8,typenum::consts::U256>;
pub type I32F32=crate::fixed::Fixed<1,32>;
pub type I64F64=crate::fixed::Fixed<2,64>;
pub type I128F128=crate::fixed::Fixed<4,128>;
pub type I256F256=crate::fixed::Fixed<8,256>;

53
fixed_wide/src/zeroes.rs Normal file

@ -0,0 +1,53 @@
use crate::fixed::Fixed;
use crate::ratio::Ratio;
use arrayvec::ArrayVec;
use std::cmp::Ordering;
macro_rules! impl_zeroes{
($n:expr)=>{
impl Fixed<$n,{$n*32}>{
#[inline]
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.[<wide_mul_ $n _ $n>](a1)-a2.[<wide_mul_ $n _ $n>](a0)*4;
}
match radicand.cmp(&Fixed::<{$n*2},{$n*2*32}>::ZERO){
Ordering::Greater=>{
let planar_radicand=radicand.sqrt().halve_precision();
//sort roots ascending and avoid taking the difference of large numbers
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([Ratio::new(a1,a2*-2)]),
Ordering::Less=>ArrayVec::new_const(),
}
}
#[inline]
pub fn zeroes1(a0:Self,a1:Self)->ArrayVec<Ratio<Self,Self>,1>{
if a1==Self::ZERO{
ArrayVec::new_const()
}else{
ArrayVec::from_iter([Ratio::new(-a0,a1)])
}
}
}
};
}
impl_zeroes!(1);
impl_zeroes!(2);
impl_zeroes!(3);
impl_zeroes!(4);
//sqrt doubles twice!
//impl_zeroes!(5);
//impl_zeroes!(6);
//impl_zeroes!(7);
//impl_zeroes!(8);

@ -1 +0,0 @@
/target

@ -1,63 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "az"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973"
[[package]]
name = "bytemuck"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fd4c6dcc3b0aea2f5c0b4b82c2b15fe39ddbc76041a310848f4706edf76bb31"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "fixed"
version = "1.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85c6e0b89bf864acd20590dbdbad56f69aeb898abfc9443008fd7bd48b2cc85a"
dependencies = [
"az",
"bytemuck",
"half",
"typenum",
]
[[package]]
name = "fixed_wide_traits"
version = "0.1.0"
dependencies = [
"fixed",
"typenum",
]
[[package]]
name = "half"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888"
dependencies = [
"cfg-if",
"crunchy",
]
[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"

@ -1,10 +0,0 @@
[package]
name = "fixed_wide_traits"
version = "0.1.0"
edition = "2021"
[dependencies]
[dev-dependencies]
fixed = "1.28.0"
typenum = "1.17.0"

@ -1,2 +0,0 @@
pub mod wide;
pub mod narrow;

@ -1,57 +0,0 @@
pub trait Narrow{
type Output;
fn narrow(self)->Self::Output;
}
#[derive(Debug)]
pub enum Error{
Overflow,
Underflow,
}
impl std::fmt::Display for Error{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
write!(f,"{self:?}")
}
}
impl std::error::Error for Error{}
pub trait TryNarrow{
type Output;
fn try_narrow(self)->Result<Self::Output,Error>;
}
#[cfg(test)]
mod tests {
use super::*;
//TODO: use num_traits to do a blanket implementation (self<T::MIN as U)
impl TryNarrow for i16{
type Output=i8;
fn try_narrow(self)->Result<Self::Output,Error>{
if self<i8::MIN as i16{
return Err(Error::Underflow);
}
if (i8::MAX as i16)<self{
return Err(Error::Overflow);
}
Ok(self as i8)
}
}
#[test]
fn test_i16_i8(){
assert!(matches!(257i16.try_narrow(),Err(Error::Overflow)));
assert!(matches!(64i16.try_narrow(),Ok(64i8)));
assert!(matches!((-257i16).try_narrow(),Err(Error::Underflow)));
}
impl Narrow for fixed::FixedI16<typenum::consts::U8>{
type Output=i8;
fn narrow(self)->Self::Output{
(self.to_bits()>>8) as i8
}
}
#[test]
fn test_fixed_i16_i8(){
let a=fixed::FixedI16::<typenum::consts::U8>::from(5)/2;
assert_eq!(a.narrow(),2);
}
}

@ -1,16 +0,0 @@
pub trait WideMul<Rhs=Self>{
type Output;
fn wide_mul(self,rhs:Rhs)->Self::Output;
}
pub trait WideDiv<Rhs=Self>{
type Output;
fn wide_div(self,rhs:Rhs)->Self::Output;
}
pub trait WideDot<Rhs=Self>{
type Output;
fn wide_dot(self,rhs:Rhs)->Self::Output;
}
pub trait WideCross<Rhs=Self>{
type Output;
fn wide_cross(self,rhs:Rhs)->Self::Output;
}

@ -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,25 +18,21 @@ checksum = "3e31ea183f6ee62ac8b8a8cf7feddd766317adfb13ff469de57ce033efd6a790"
name = "fixed_wide"
version = "0.1.0"
dependencies = [
"arrayvec",
"bnum",
"fixed_wide_traits",
"typenum",
"paste",
]
[[package]]
name = "fixed_wide_traits"
version = "0.1.0"
[[package]]
name = "fixed_wide_vectors"
version = "0.1.0"
dependencies = [
"fixed_wide",
"fixed_wide_traits",
"paste",
]
[[package]]
name = "typenum"
version = "1.17.0"
name = "paste"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"

@ -4,11 +4,9 @@ version = "0.1.0"
edition = "2021"
[features]
default=["fixed_wide_traits"]
fixed_wide_traits=["dep:fixed_wide_traits"]
default=["fixed_wide"]
fixed_wide=["dep:fixed_wide"]
[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" }
fixed_wide = { version = "0.1.0", path = "../fixed_wide", optional = true }
paste = "1.0.15"

@ -0,0 +1,138 @@
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_common {
( $struct: ident { $($field: 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 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> 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() } ), +
}
}
}
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()
}
}
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: 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: Copy> Copy for $struct<T> { }
impl<T: Default> Default for $struct<T> {
fn default() -> Self {
Self {
$( $field: T::default() ), +
}
}
}
}
}

@ -0,0 +1,274 @@
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_wide_vector_operations_2arg_not_const_generic {
(
($struct: ident { $($field: ident), + }, $size: expr),
($lhs:expr, $rhs:expr)
) => {
impl $struct<fixed_wide::fixed::Fixed<{$lhs},{$lhs*32}>>{
paste::item!{
#[inline]
pub fn [<wide_mul_ $lhs _ $rhs>](self,rhs:$struct<fixed_wide::fixed::Fixed<{$rhs},{$rhs*32}>>)->$struct<fixed_wide::fixed::Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>>{
$struct{
$( $field: self.$field.[<wide_mul_ $lhs _ $rhs>](rhs.$field) ), +
}
}
#[inline]
pub fn [<wide_dot_ $lhs _ $rhs>](self,rhs:$struct<fixed_wide::fixed::Fixed<{$rhs},{$rhs*32}>>)->fixed_wide::fixed::Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>{
$crate::sum_repeating!(
$( + (self.$field.[<wide_mul_ $lhs _ $rhs>](rhs.$field)) ) +
)
}
}
}
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_wide_vector_operations_1arg_not_const_generic {
(
($struct: ident { $($field: ident), + }, $size: expr),
$n:expr
) => {
impl $struct<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}>{
$crate::sum_repeating!(
$( + self.$field.[<wide_mul_ $n _ $n>](self.$field) ) +
)
}
}
}
};
}
#[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 {
( $struct: ident { $($field: ident), + }, $size: expr ) => {
$crate::do_macro_8!(impl_wide_vector_operations_1arg_not_const_generic,($struct { $($field), + }, $size));
$crate::do_macro_8x8!(impl_wide_vector_operations_2arg_not_const_generic,($struct { $($field), + }, $size));
};
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_mul_transpose_helper {
(
$lhs_axis:expr, $wide_mul:ident, $rhs:ident,
($struct: ident { $($field: ident), + }),
($from_struct: ident { $($from_field: ident), + }),
$static_field: ident
) => {
$crate::sum_repeating!(
$( + $lhs_axis.$field.$wide_mul($rhs.$from_field.$static_field) ) +
)
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_mul_inner {
(
// MatY<VecX>.MatX<VecZ> = MatY<VecZ>
$lhs:ident, $lhs_field_outer:ident, $wide_mul:ident, $rhs:ident,
$struct_inner_thru: tt, //VecX
($struct_inner: ident { $($field_inner: ident), + }), //VecX
($rhs_struct_inner: ident { $($rhs_field_inner: ident), + }), //VecZ
$rhs_outer: tt //MatX
) => {
$rhs_struct_inner {
$(
//directly dot product to avoid a copy
$rhs_field_inner: $crate::impl_matrix_wide_mul_transpose_helper!{
//lhs_axis
$lhs.$lhs_field_outer,$wide_mul,$rhs,
$struct_inner_thru, //VecZ
$rhs_outer, //MatX
$rhs_field_inner
}
), +
}
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_mul_outer {
(
// MatY<VecX>.MatX<VecZ> = MatY<VecZ>
$lhs:ident, $wide_mul:ident, $rhs:ident,
//result matrix shape
($struct_outer: ident { $($field_outer: ident), + }),//MatY
$rhs_struct_inner: tt,//VecZ
//inner loop shape
$struct_inner: tt,//VecX
$rhs_matrix: tt//MatX
) => {
$struct_outer {
$(
$field_outer: $crate::impl_matrix_wide_mul_inner!{
$lhs, $field_outer, $wide_mul, $rhs,
$struct_inner, //VecX
$struct_inner, //VecX
$rhs_struct_inner, //VecZ
$rhs_matrix //MatX
}
), +
}
}
}
// Notes:
// Mat3<Vec2>.dot(Vec2) -> Vec3
// lhs.dot(rhs) -> out
// lhs = Mat3<Vec4>
// rhs = Mat4<Vec2>
// out = Mat3<Vec2>
// Mat3<Vec4>.dot(Mat4<Vec2>) -> Mat3<Vec2>
// how to matrix multiply:
// RHS TRANSPOSE
// Mat4<Vec2> -> Mat2<Vec4>
// rhs_t = Mat2<Vec4>
// inner loop:
// out[y][x] = lhs[y].dot(rhs_t[x])
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_mul {
(
($struct_outer: ident { $($field_outer: ident), + }, $vector_outer: ident { $($vector_field_outer: ident), + }, $size_outer: expr),
($struct_inner: ident { $($field_inner: ident), + }, $matrix_inner: ident { $($matrix_field_inner: ident), + }, $size_inner: expr),
($rhs_struct_inner: ident { $($rhs_field_inner: ident), + }, $rhs_matrix_inner: ident { $($rhs_matrix_field_inner: ident), + }, $rhs_size_inner: expr),
($lhs: expr, $rhs: expr)
) => {
impl $struct_outer<$struct_inner<fixed_wide::fixed::Fixed<{$lhs},{$lhs*32}>>>{
paste::item!{
#[inline]
pub fn [<wide_dot_ $size_outer x $size_inner _ $size_inner x $rhs_size_inner _ $lhs _ $rhs>](self,rhs:$matrix_inner<$rhs_struct_inner<fixed_wide::fixed::Fixed<{$rhs},{$rhs*32}>>>)->$struct_outer<$rhs_struct_inner<fixed_wide::fixed::Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>>>{
$crate::impl_matrix_wide_mul_outer!(
//constituent idents
self,[<wide_mul_ $lhs _ $rhs>],rhs,
//result matrix shape
($struct_outer { $($field_outer), + }),
($rhs_struct_inner { $($rhs_field_inner), + }),
//inner loop shape
($struct_inner { $($field_inner), + }),
($matrix_inner { $($matrix_field_inner), + })
)
}
}
}
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_mul_shim {
(
($outer_info:tt,$inner_info:tt,$rhs_info:tt),
($lhs: expr, $rhs: expr)
) => {
$crate::impl_matrix_wide_mul!($outer_info,$inner_info,$rhs_info,($lhs,$rhs));
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_mul_8x8 {
(
($outer_info:tt,$inner_info:tt),
$rhs_info:tt
) => {
$crate::do_macro_8x8!(impl_matrix_wide_mul_shim,($outer_info,$inner_info,$rhs_info));
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_mul_repeat_rhs {
(
($outer_info:tt,($($rhs_info:tt),+)),
$inner_info:tt
) => {
$crate::macro_repeated!(impl_matrix_wide_mul_8x8,($outer_info,$inner_info),$($rhs_info),+);
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_wide_matrix_operations_2arg_not_const_generic {
(
$lhs: expr, $rhs: expr,
($struct_outer: ident { $($field_outer: ident), + }, $vector_outer: ident { $($vector_field_outer: ident), + }, $size_outer: expr),
($struct_inner: ident { $($field_inner: ident), + }, $matrix_inner: ident { $($matrix_field_inner: ident), + }, $size_inner: expr)
) => {
/* TODO: nasty determinant macro
impl<U:std::ops::Add<Output=U>,T:Copy+fixed_wide_traits::wide::WideMul<Output=U>> $struct<T> {
#[inline]
pub fn wide_dot(&self) -> U {
$crate::sum_repeating!(
$( + self.$field.wide_mul(self.$field) ) +
)
}
}
*/
};
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_wide_matrix_operations_1arg_not_const_generic {
(
$n: expr,
($struct_outer: ident { $($field_outer: ident), + }, $vector_outer: ident { $($vector_field_outer: ident), + }, $size_outer: expr),
) => {
/* TODO: nasty determinant macro
impl<U:std::ops::Add<Output=U>,T:Copy+fixed_wide_traits::wide::WideMul<Output=U>> $struct<T> {
#[inline]
pub fn wide_det(&self) -> U {
$crate::sum_repeating!(
$( + self.$field.wide_mul(self.$field) ) +
)
}
}
*/
};
}
// HACK: Allows us to sum repeating tokens in macros.
// See: https://stackoverflow.com/a/60187870/17452730
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! sum_repeating {
( + $($item: tt) * ) => {
$($item) *
};
}

@ -2,10 +2,61 @@
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix {
(
($struct_outer: ident { $($field_outer: ident), + }, $vector_outer: ident { $($vector_field_outer: ident), + }, $size_outer: expr)
) => {
$crate::impl_common!($struct_outer { $($field_outer), + }, $size_outer);
impl<U> $struct_outer<U> {
#[inline(always)]
pub fn to_vector(self) -> $vector_outer<U> {
$vector_outer {
$(
$vector_field_outer: self.$field_outer
), +
}
}
}
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_shim {
(
(),
$matrix_info:tt
) => {
$crate::impl_matrix!($matrix_info);
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrices {
(
($($matrix_info:tt),+),
$vector_infos:tt
) => {
$crate::macro_repeated!(impl_matrix_shim,(),$($matrix_info),+);
$crate::macro_repeated!(impl_matrix_inner_shim,$vector_infos,$($matrix_info),+);
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_inner_shim {
(
($($vector_info:tt),+),
$matrix_info:tt
) => {
$crate::macro_repeated!(impl_matrix_inner,$matrix_info,$($vector_info),+);
#[cfg(feature="fixed_wide")]
$crate::macro_repeated!(impl_matrix_wide_mul_repeat_rhs,($matrix_info,($($vector_info),+)),$($vector_info),+);
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_inner {
(
($struct_outer: ident { $($field_outer: ident), + }, $vector_outer: ident { $($vector_field_outer: ident), + }, $size_outer: expr),
($struct_inner: ident { $($field_inner: ident), + }, $matrix_inner: ident { $($matrix_field_inner: ident), + }, $size_inner: expr),
( $($generic_outer: tt), + )
($struct_inner: ident { $($field_inner: ident), + }, $matrix_inner: ident { $($matrix_field_inner: ident), + }, $size_inner: expr)
) => {
impl<T> $struct_outer<$struct_inner<T>> {
#[inline(always)]
@ -13,11 +64,6 @@ macro_rules! impl_matrix {
[ $(self.$field_outer.to_array()), + ]
}
#[inline(always)]
pub fn to_tuple_2d(self) -> ( $($generic_outer), + ) {
( $(self.$field_outer.to_tuple()), + )
}
#[inline]
pub fn map_2d<F, U>(self, f: F) -> $struct_outer<$struct_inner<U>>
where
@ -106,22 +152,6 @@ macro_rules! matrix_transpose_inner {
}
}
/*
macro_rules! nested {
(($($f:ident),*) $args:tt) => {
$(nested!(@call $f $args);)*
};
(@call $f:ident ($($arg:expr),*)) => {
$f($($arg),*);
};
}
nested! {
(show1, show2)
(a, b, c)
}
*/
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_operator {

@ -1,5 +1,20 @@
#[cfg(feature="fixed_wide_traits")]
pub mod wide;
#[cfg(feature="fixed_wide")]
pub mod fixed_wide;
pub mod common;
pub mod vector;
pub mod matrix;
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! macro_repeated{
(
$macro:ident,
$any:tt,
$($repeated:tt),*
)=>{
$(
$crate::$macro!($any, $repeated);
)*
};
}

@ -2,166 +2,8 @@
#[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 ), +
}
}
/// 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 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> 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() } ), +
}
}
}
impl<T> From<($($generic), +)> for $struct<T> {
fn from(from: ($($generic), +)) -> Self {
let ( $($field), + ) = from;
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);
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: 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: Clone> Clone for $struct<T> {
fn clone(&self) -> Self {
Self {
$( $field: self.$field.clone() ), +
}
}
}
impl<T: Copy> Copy for $struct<T> { }
impl<T: Default> Default for $struct<T> {
fn default() -> Self {
Self {
$( $field: T::default() ), +
}
}
}
( $struct: ident { $($field: ident), + }, $size: expr ) => {
$crate::impl_common!($struct { $($field), + }, $size);
impl<T: Ord> $struct<T> {
pub fn min(self, rhs: Self) -> $struct<T> {
@ -242,7 +84,7 @@ macro_rules! impl_vector {
$crate::impl_vector_operator!( $struct { $($field), + }, BitXor, bitxor, Self );
// Impl floating-point based methods
#[cfg(feature="fixed_wide_traits")]
#[cfg(feature="fixed_wide")]
$crate::impl_wide_vector_operations!( $struct { $($field), + }, $size );
};
}

@ -1,43 +0,0 @@
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_wide_vector_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> {
type Output=$struct<U>;
#[inline]
fn wide_mul(self, rhs: Self) -> Self::Output {
$struct{
$( $field: self.$field.wide_mul(rhs.$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) ) +
)
}
}
};
}
// HACK: Allows us to sum repeating tokens in macros.
// See: https://stackoverflow.com/a/60187870/17452730
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! sum_repeating {
( + $($item: tt) * ) => {
$($item) *
};
}

@ -18,13 +18,19 @@ pub struct Matrix4<T> {
crate::impl_extend!(Matrix2 { x_axis, y_axis }, Matrix3, z_axis);
crate::impl_extend!(Matrix3 { x_axis, y_axis, z_axis }, Matrix4, w_axis);
//TODO: extend vertically
crate::impl_matrix!((Matrix2 { x_axis, y_axis }, Vector2 { x, y }, 2), (Vector2 { x, y }, Matrix2 { x_axis, y_axis }, 2), ((T, T), (T, T)) );
crate::impl_matrix!((Matrix2 { x_axis, y_axis }, Vector2 { x, y }, 2), (Vector3 { x, y, z }, Matrix3 { x_axis, y_axis, z_axis }, 3), ((T, T, T), (T, T, T)) );
crate::impl_matrix!((Matrix2 { x_axis, y_axis }, Vector2 { x, y }, 2), (Vector4 { x, y, z, w }, Matrix4 { x_axis, y_axis, z_axis, w_axis }, 4), ((T, T, T, T), (T, T, T, T)) );
crate::impl_matrix!((Matrix3 { x_axis, y_axis, z_axis }, Vector3 { x, y, z }, 3), (Vector2 { x, y }, Matrix2 { x_axis, y_axis }, 2), ((T, T), (T, T), (T, T)) );
crate::impl_matrix!((Matrix3 { x_axis, y_axis, z_axis }, Vector3 { x, y, z }, 3), (Vector3 { x, y, z }, Matrix3 { x_axis, y_axis, z_axis }, 3), ((T, T, T), (T, T, T), (T, T, T)) );
crate::impl_matrix!((Matrix3 { x_axis, y_axis, z_axis }, Vector3 { x, y, z }, 3), (Vector4 { x, y, z, w }, Matrix4 { x_axis, y_axis, z_axis, w_axis }, 4), ((T, T, T, T), (T, T, T, T), (T, T, T, T)) );
crate::impl_matrix!((Matrix4 { x_axis, y_axis, z_axis, w_axis }, Vector4 { x, y, z, w }, 4), (Vector2 { x, y }, Matrix2 { x_axis, y_axis }, 2), ((T, T), (T, T), (T, T), (T, T)) );
crate::impl_matrix!((Matrix4 { x_axis, y_axis, z_axis, w_axis }, Vector4 { x, y, z, w }, 4), (Vector3 { x, y, z }, Matrix3 { x_axis, y_axis, z_axis }, 3), ((T, T, T), (T, T, T), (T, T, T), (T, T, T)) );
crate::impl_matrix!((Matrix4 { x_axis, y_axis, z_axis, w_axis }, Vector4 { x, y, z, w }, 4), (Vector4 { x, y, z, w }, Matrix4 { x_axis, y_axis, z_axis, w_axis }, 4), ((T, T, T, T), (T, T, T, T), (T, T, T, T), (T, T, T, T)) );
crate::impl_matrices!(
//outer struct and equivalent vector
(
(Matrix2 { x_axis, y_axis }, Vector2 { x, y }, 2),
(Matrix3 { x_axis, y_axis, z_axis }, Vector3 { x, y, z }, 3),
(Matrix4 { x_axis, y_axis, z_axis, w_axis }, Vector4 { x, y, z, w }, 4)
),
//inner struct and equivalent matrix
(
(Vector2 { x, y }, Matrix2 { x_axis, y_axis }, 2),
(Vector3 { x, y, z }, Matrix3 { x_axis, y_axis, z_axis }, 3),
(Vector4 { x, y, z, w }, Matrix4 { x_axis, y_axis, z_axis, w_axis }, 4)
)
);

@ -0,0 +1,63 @@
use crate::{Vector2,Vector3,Vector4,Matrix3,Matrix4};
type Planar64=fixed_wide::types::I32F32;
type Planar64Wide1=fixed_wide::types::I64F64;
//type Planar64Wide2=fixed_wide::types::I128F128;
type Planar64Wide3=fixed_wide::types::I256F256;
#[test]
fn wide_vec3(){
let v=Vector3::from_value(Planar64::from(3));
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,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_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));
}
#[test]
fn wide_vec3_length_squared(){
let v=Vector3::from_value(Planar64::from(3));
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));
}
#[test]
fn wide_matrix_dot(){
let lhs=Matrix3::from([
Vector4::from([Planar64::from(1),Planar64::from(2),Planar64::from(3),Planar64::from(4)]),
Vector4::from([Planar64::from(5),Planar64::from(6),Planar64::from(7),Planar64::from(8)]),
Vector4::from([Planar64::from(9),Planar64::from(10),Planar64::from(11),Planar64::from(12)]),
]);
let rhs=Matrix4::from([
Vector2::from([Planar64::from(1),Planar64::from(2)]),
Vector2::from([Planar64::from(3),Planar64::from(4)]),
Vector2::from([Planar64::from(5),Planar64::from(6)]),
Vector2::from([Planar64::from(7),Planar64::from(8)]),
]);
// Mat3<Vec4>.dot(Mat4<Vec2>) -> Mat3<Vec2>
let m_dot=lhs.wide_dot_3x4_4x2_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!(
m_dot,
Matrix3::from([
Vector2::from([Planar64Wide1::from(50),Planar64Wide1::from(60)]),
Vector2::from([Planar64Wide1::from(114),Planar64Wide1::from(140)]),
Vector2::from([Planar64Wide1::from(178),Planar64Wide1::from(220)]),
])
);
}

@ -1,68 +0,0 @@
use fixed_wide_traits::wide::WideMul;
use fixed_wide_traits::wide::WideDot;
use crate::{Vector2,Vector3,Matrix3};
type Planar64=fixed_wide::types::I32F32;
type Planar64Wide1=fixed_wide::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));
}
#[test]
fn wide_vec_of_vec_dot(){
let vv=Vector3::<Vector2<_>>::from_value_2d(Planar64::from(3));
// do the dot product of the inner vectors multiplied component wise
// this lowers the rank of the data structure and is kind of a weird operation lol
let vv_dot=vv.wide_dot(vv);
assert_eq!(vv_dot,Vector2::from_value(Planar64Wide1::from(3i128.pow(3))));
}
#[test]
fn wide_matrix_dot(){
let m=Matrix3::<Vector3<_>>::from_value_2d(Planar64::from(3));
//normal matrix product
todo!()
//let m_dot=m.wide_dot(m);
//assert_eq!(m_dot,Matrix3::<Vector3<_>>::from_value_2d(Planar64Wide1::from(3i128.pow(2))));
}

@ -1,5 +1,5 @@
mod tests;
#[cfg(feature="fixed_wide_traits")]
mod fixed_wide_traits;
#[cfg(feature="fixed_wide")]
mod fixed_wide;

@ -1,16 +1 @@
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))
}

@ -63,19 +63,19 @@ pub struct Vector4<T> {
}
crate::impl_vector!(Vector2 { x, y }, (T, T), 2);
crate::impl_vector!(Vector3 { x, y, z }, (T, T, T), 3);
crate::impl_vector!(Vector4 { x, y, z, w }, (T, T, T, T), 4);
crate::impl_vector!(Vector2 { x, y }, 2);
crate::impl_vector!(Vector3 { x, y, z }, 3);
crate::impl_vector!(Vector4 { x, y, z, w }, 4);
crate::impl_extend!(Vector2 { x, y }, Vector3, z);
crate::impl_extend!(Vector3 { x, y, z }, Vector4, w);
crate::impl_matrix!((Vector2 { x, y }, Vector2 { x, y }, 2), (Vector2 { x, y }, Vector2 { x, y }, 2), ((T, T), (T, T)) );
crate::impl_matrix!((Vector2 { x, y }, Vector2 { x, y }, 2), (Vector3 { x, y, z }, Vector3 { x, y, z }, 3), ((T, T, T), (T, T, T)) );
crate::impl_matrix!((Vector2 { x, y }, Vector2 { x, y }, 2), (Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4), ((T, T, T, T), (T, T, T, T)) );
crate::impl_matrix!((Vector3 { x, y, z }, Vector3 { x, y, z }, 3), (Vector2 { x, y }, Vector2 { x, y }, 2), ((T, T), (T, T), (T, T)) );
crate::impl_matrix!((Vector3 { x, y, z }, Vector3 { x, y, z }, 3), (Vector3 { x, y, z }, Vector3 { x, y, z }, 3), ((T, T, T), (T, T, T), (T, T, T)) );
crate::impl_matrix!((Vector3 { x, y, z }, Vector3 { x, y, z }, 3), (Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4), ((T, T, T, T), (T, T, T, T), (T, T, T, T)) );
crate::impl_matrix!((Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4), (Vector2 { x, y }, Vector2 { x, y }, 2), ((T, T), (T, T), (T, T), (T, T)) );
crate::impl_matrix!((Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4), (Vector3 { x, y, z }, Vector3 { x, y, z }, 3), ((T, T, T), (T, T, T), (T, T, T), (T, T, T)) );
crate::impl_matrix!((Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4), (Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4), ((T, T, T, T), (T, T, T, T), (T, T, T, T), (T, T, T, T)) );
crate::impl_matrix_inner!((Vector2 { x, y }, Vector2 { x, y }, 2), (Vector2 { x, y }, Vector2 { x, y }, 2) );
crate::impl_matrix_inner!((Vector2 { x, y }, Vector2 { x, y }, 2), (Vector3 { x, y, z }, Vector3 { x, y, z }, 3) );
crate::impl_matrix_inner!((Vector2 { x, y }, Vector2 { x, y }, 2), (Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4) );
crate::impl_matrix_inner!((Vector3 { x, y, z }, Vector3 { x, y, z }, 3), (Vector2 { x, y }, Vector2 { x, y }, 2) );
crate::impl_matrix_inner!((Vector3 { x, y, z }, Vector3 { x, y, z }, 3), (Vector3 { x, y, z }, Vector3 { x, y, z }, 3) );
crate::impl_matrix_inner!((Vector3 { x, y, z }, Vector3 { x, y, z }, 3), (Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4) );
crate::impl_matrix_inner!((Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4), (Vector2 { x, y }, Vector2 { x, y }, 2) );
crate::impl_matrix_inner!((Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4), (Vector3 { x, y, z }, Vector3 { x, y, z }, 3) );
crate::impl_matrix_inner!((Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4), (Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4) );