Compare commits
84 Commits
Author | SHA1 | Date | |
---|---|---|---|
c51dc6098c | |||
6aba246453 | |||
f7ae745bef | |||
1f1568ebe9 | |||
176eb762e3 | |||
15bd78c0e1 | |||
0f9d0c8c39 | |||
eefbdafc16 | |||
b0ecfeb294 | |||
48a8271b99 | |||
1604888254 | |||
4017f33447 | |||
f0527714db | |||
27d96f9b19 | |||
a5094fe873 | |||
1bd45283a9 | |||
a6dc0c37ba | |||
83434a89c7 | |||
b14c84bdad | |||
e98744871b | |||
c26ce93fc8 | |||
c856509759 | |||
5cb98ee29f | |||
bc29cd9848 | |||
502ab7f33f | |||
e0dba8840e | |||
4d13b4ada7 | |||
2a2e729f59 | |||
63cf94499b | |||
83a39468d5 | |||
9aba811cd0 | |||
e413409f9f | |||
e6a28fbb70 | |||
88acec5659 | |||
0f0d7f7a9a | |||
263f0d35d4 | |||
d713b96ad3 | |||
20285f0f98 | |||
f103c247b8 | |||
8e1807b4b7 | |||
f531e8d8ee | |||
78f860c672 | |||
0924518922 | |||
46d89619bd | |||
540749e4f1 | |||
3c5f01da89 | |||
70a79a8d25 | |||
0483c9eb27 | |||
61aad93f8d | |||
cd1aa26293 | |||
b656371142 | |||
9266edbf92 | |||
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 |
deferred_division
fixed_wide
fixed_wide_traits
fixed_wide_vectors
1
deferred_division/.gitignore
vendored
1
deferred_division/.gitignore
vendored
@ -1 +0,0 @@
|
||||
/target
|
14
deferred_division/Cargo.lock
generated
14
deferred_division/Cargo.lock
generated
@ -1,14 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "deferred_division"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"fixed_wide_traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fixed_wide_traits"
|
||||
version = "0.1.0"
|
@ -1,11 +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 }
|
@ -1,8 +0,0 @@
|
||||
pub mod ratio;
|
||||
|
||||
|
||||
#[cfg(feature="fixed_wide_traits")]
|
||||
mod wide;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
@ -1,10 +0,0 @@
|
||||
#[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;
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
use std::ops::{Add,Mul};
|
||||
use crate::ratio::Ratio;
|
||||
use fixed_wide_traits::wide::{WideMul,WideDiv};
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
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
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,127 +1,377 @@
|
||||
use bnum::BInt;
|
||||
use typenum::Unsigned;
|
||||
use std::marker::PhantomData;
|
||||
use bnum::{BInt,cast::As};
|
||||
|
||||
#[derive(Clone,Copy,Debug,Hash)]
|
||||
pub struct Fixed<const CHUNKS:usize,Frac>{
|
||||
pub(crate)bits:BInt<{CHUNKS}>,
|
||||
pub(crate)frac: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 ZERO:Self=Self{bits:BInt::<CHUNKS>::ZERO,frac:PhantomData};
|
||||
pub const ONE:Self=Self{bits:BInt::<CHUNKS>::ONE.shl(Frac::U32),frac:PhantomData};
|
||||
pub const NEG_ONE:Self=Self{bits:BInt::<CHUNKS>::NEG_ONE.shl(Frac::U32),frac:PhantomData};
|
||||
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,FracDst:Unsigned,T> From<T> for Fixed<CHUNKS,FracDst>
|
||||
where
|
||||
BInt<CHUNKS>:From<T>
|
||||
{
|
||||
fn from(value:T)->Self{
|
||||
impl<const N:usize,const F:usize> Fixed<N,F>{
|
||||
#[inline]
|
||||
pub const fn from_bits(bits:BInt::<N>)->Self{
|
||||
Self{
|
||||
bits:BInt::<{CHUNKS}>::from(value)<<FracDst::U32,
|
||||
frac:PhantomData,
|
||||
bits,
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub const fn to_bits(self)->BInt<N>{
|
||||
self.bits
|
||||
}
|
||||
#[inline]
|
||||
pub const fn raw(value:i64)->Self{
|
||||
Self::from_bits(BInt::from_bits(bnum::BUint::from_digit(value as u64)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<const CHUNKS:usize,Frac> PartialEq for Fixed<CHUNKS,Frac>{
|
||||
impl<const N:usize,const F:usize,T> From<T> for Fixed<N,F>
|
||||
where
|
||||
BInt<N>:From<T>
|
||||
{
|
||||
fn from(value:T)->Self{
|
||||
Self::from_bits(BInt::<{N}>::from(value)<<F as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N:usize,const F:usize> PartialEq for Fixed<N,F>{
|
||||
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{
|
||||
bits:self.bits.neg(),
|
||||
frac:PhantomData,
|
||||
}
|
||||
Self::from_bits(self.bits.neg())
|
||||
}
|
||||
}
|
||||
|
||||
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 N:usize,const F:usize> core::ops::$trait for $struct<N,F>{
|
||||
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::from_bits(self.bits.$method(other.bits))
|
||||
}
|
||||
}
|
||||
impl<const N:usize,const F:usize,U> core::ops::$trait<U> for $struct<N,F>
|
||||
where
|
||||
BInt::<N>:From<U>,
|
||||
{
|
||||
type Output = $output;
|
||||
|
||||
fn $method(self, other: U) -> Self::Output {
|
||||
Self::from_bits(self.bits.$method(BInt::<N>::from(other).shl(F as u32)))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
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 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 N:usize,const F:usize,U> core::ops::$trait<U> for $struct<N,F>
|
||||
where
|
||||
BInt::<N>:From<U>,
|
||||
{
|
||||
fn $method(&mut self, other: U) {
|
||||
self.bits.$method(BInt::<N>::from(other)<<F as 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<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(F as u32).as_())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
macro_rules! impl_multiply_assign_operator_const {
|
||||
( $width:expr, $struct: ident, $trait: ident, $method: ident ) => {
|
||||
impl<const F:usize> core::ops::$trait for $struct<$width,F>{
|
||||
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<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+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_())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
macro_rules! impl_divide_assign_operator_const {
|
||||
( $width:expr, $struct: ident, $trait: ident, $method: ident ) => {
|
||||
impl<const F:usize> core::ops::$trait for $struct<$width,F>{
|
||||
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 N:usize,const F:usize,U> core::ops::$trait<U> for $struct<N,F>
|
||||
where
|
||||
BInt::<N>:From<U>+core::ops::$trait,
|
||||
{
|
||||
type Output = $output;
|
||||
|
||||
fn $method(self, other: U) -> Self::Output {
|
||||
Self::from_bits(self.bits.$method(BInt::<N>::from(other)))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
macro_rules! impl_multiplicatave_assign_operator {
|
||||
( $struct: ident, $trait: ident, $method: ident ) => {
|
||||
impl<const N:usize,const F:usize,U> core::ops::$trait<U> for $struct<N,F>
|
||||
where
|
||||
BInt::<N>:From<U>+core::ops::$trait,
|
||||
{
|
||||
fn $method(&mut self, other: U) {
|
||||
self.bits.$method(BInt::<N>::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 N:usize,const F:usize> core::ops::$trait<u32> for $struct<N,F>{
|
||||
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::from_bits(self.bits.$method(other))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
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 N:usize,const F:usize> core::ops::$trait<u32> for $struct<N,F>{
|
||||
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 );
|
||||
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,44 +0,0 @@
|
||||
use bnum::BInt;
|
||||
use bnum::cast::As;
|
||||
use typenum::{Sum,Unsigned};
|
||||
use crate::fixed::Fixed;
|
||||
use fixed_wide_traits::wide::WideMul;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
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{
|
||||
bits:self.bits.as_::<BInt<{$lhs+$rhs}>>()*rhs.bits.as_::<BInt<{$lhs+$rhs}>>(),
|
||||
frac:PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
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)
|
||||
);
|
@ -1,11 +1,10 @@
|
||||
pub mod fixed;
|
||||
pub mod types;
|
||||
|
||||
pub mod typenum{
|
||||
pub use typenum::Unsigned;
|
||||
}
|
||||
#[cfg(feature="zeroes")]
|
||||
pub mod zeroes;
|
||||
#[cfg(feature="ratio")]
|
||||
pub mod ratio;
|
||||
|
||||
#[cfg(feature="fixed_wide_traits")]
|
||||
mod fixed_wide_traits;
|
||||
#[cfg(feature="fixed_wide_traits")]
|
||||
pub use ::fixed_wide_traits::wide;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
10
fixed_wide/src/ratio.rs
Normal file
10
fixed_wide/src/ratio.rs
Normal file
@ -0,0 +1,10 @@
|
||||
#[derive(Clone,Copy,Debug,Hash)]
|
||||
pub struct Ratio<Num,Den>{
|
||||
pub(crate)num:Num,
|
||||
pub(crate)den:Den,
|
||||
}
|
||||
impl<Num,Den> Ratio<Num,Den>{
|
||||
pub const fn new(num:Num,den:Den)->Self{
|
||||
Self{num,den}
|
||||
}
|
||||
}
|
90
fixed_wide/src/tests.rs
Normal file
90
fixed_wide/src/tests.rs
Normal file
@ -0,0 +1,90 @@
|
||||
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_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;
|
||||
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_zero(){
|
||||
let a=I32F32::ZERO;
|
||||
assert_eq!(a.sqrt(),I32F32::ZERO);
|
||||
}
|
||||
#[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_1_1(r+I32F32::EPSILON)==n.wide_mul_1_1(I32F32::ONE){
|
||||
return r+I32F32::EPSILON;
|
||||
}
|
||||
if (r-I32F32::EPSILON).wide_mul_1_1(r-I32F32::EPSILON)==n.wide_mul_1_1(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,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
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
fixed_wide_traits/.gitignore
vendored
1
fixed_wide_traits/.gitignore
vendored
@ -1 +0,0 @@
|
||||
/target
|
63
fixed_wide_traits/Cargo.lock
generated
63
fixed_wide_traits/Cargo.lock
generated
@ -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;
|
||||
}
|
22
fixed_wide_vectors/Cargo.lock
generated
22
fixed_wide_vectors/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,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"
|
||||
|
@ -1,17 +0,0 @@
|
||||
use std::ops::Add;
|
||||
use fixed_wide_traits::wide::WideDot;
|
||||
|
||||
pub struct Affine<M,T>{
|
||||
pub matrix:M,
|
||||
pub offset:T,
|
||||
}
|
||||
|
||||
impl<M:Copy,T:Copy> Affine<M,T>{
|
||||
pub fn wide_transform<X>(&self,input:X)-><<M as WideDot<X>>::Output as Add<T>>::Output
|
||||
where
|
||||
M:WideDot<X>,
|
||||
<M as WideDot<X>>::Output:Add<T>,
|
||||
{
|
||||
self.matrix.wide_dot(input)+self.offset
|
||||
}
|
||||
}
|
@ -1,12 +1,14 @@
|
||||
mod macros;
|
||||
mod vector;
|
||||
|
||||
#[cfg(feature="fixed_wide_traits")]
|
||||
pub mod affine;
|
||||
mod matrix;
|
||||
|
||||
pub use vector::Vector2;
|
||||
pub use vector::Vector3;
|
||||
pub use vector::Vector4;
|
||||
|
||||
pub use matrix::Matrix2;
|
||||
pub use matrix::Matrix3;
|
||||
pub use matrix::Matrix4;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
138
fixed_wide_vectors/src/macros/common.rs
Normal file
138
fixed_wide_vectors/src/macros/common.rs
Normal file
@ -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() ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
274
fixed_wide_vectors/src/macros/fixed_wide.rs
Normal file
274
fixed_wide_vectors/src/macros/fixed_wide.rs
Normal file
@ -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) *
|
||||
};
|
||||
}
|
192
fixed_wide_vectors/src/macros/matrix.rs
Normal file
192
fixed_wide_vectors/src/macros/matrix.rs
Normal file
@ -0,0 +1,192 @@
|
||||
// Stolen from https://github.com/c1m50c/fixed-vectors (MIT license)
|
||||
#[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)
|
||||
) => {
|
||||
impl<T> $struct_outer<$struct_inner<T>> {
|
||||
#[inline(always)]
|
||||
pub fn to_array_2d(self) -> [[T; $size_inner]; $size_outer] {
|
||||
[ $(self.$field_outer.to_array()), + ]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn map_2d<F, U>(self, f: F) -> $struct_outer<$struct_inner<U>>
|
||||
where
|
||||
F: Fn(T) -> U
|
||||
{
|
||||
$crate::matrix_map2d_outer!{f,self,($struct_outer { $($field_outer), + }),($struct_inner { $($field_inner), + })}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn transpose(self) -> $matrix_inner<$vector_outer<T>>{
|
||||
$crate::matrix_transpose_outer!{self,
|
||||
($matrix_inner { $($matrix_field_inner), + }),($struct_inner { $($field_inner), + }),
|
||||
($vector_outer { $($vector_field_outer), + }),($struct_outer { $($field_outer), + })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy> $struct_outer<$struct_inner<T>> {
|
||||
#[inline(always)]
|
||||
pub const fn from_value_2d(value: T) -> Self {
|
||||
Self {
|
||||
$( $field_outer: $struct_inner::from_value(value) ), +
|
||||
}
|
||||
}
|
||||
//TODO: diagonal
|
||||
}
|
||||
|
||||
// Impl floating-point based methods
|
||||
//#[cfg(feature="fixed_wide_traits")]
|
||||
//$crate::impl_wide_matrix_operations!( ($struct_outer { $($field_outer), + }, $size_outer), ($struct_inner, $size_inner), $fields_inner );
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! matrix_map2d_outer {
|
||||
( $f:ident, $value:ident, ($struct_outer: ident { $($field_outer: ident), + }), $unparsed_inner:tt ) => {
|
||||
$struct_outer {
|
||||
$(
|
||||
$field_outer: $crate::matrix_map2d_inner!{$f,$value,$field_outer,$unparsed_inner}
|
||||
), +
|
||||
}
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! matrix_map2d_inner {
|
||||
( $f:ident, $value:ident, $field_outer:ident, ($struct_inner: ident { $($field_inner: ident), + }) ) => {
|
||||
$struct_inner {
|
||||
$(
|
||||
$field_inner: $f($value.$field_outer.$field_inner)
|
||||
), +
|
||||
}
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! matrix_transpose_outer {
|
||||
(
|
||||
$value:ident,
|
||||
($struct_outer: ident { $($field_outer: ident), + }),
|
||||
($old_outer: ident { $($old_field_outer: ident), + }),
|
||||
$fields_inner:tt,
|
||||
$old_fields_inner:tt
|
||||
) => {
|
||||
$struct_outer {
|
||||
$(
|
||||
$field_outer: $crate::matrix_transpose_inner!{$value,$old_field_outer,$fields_inner,$old_fields_inner}
|
||||
), +
|
||||
}
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! matrix_transpose_inner {
|
||||
( $value:ident, $field_outer:ident,
|
||||
($struct_inner: ident { $($field_inner: ident), + }),
|
||||
($old_struct_inner: ident { $($old_field_inner: ident), + })
|
||||
) => {
|
||||
$struct_inner {
|
||||
$(
|
||||
$field_inner: $value.$old_field_inner.$field_outer
|
||||
), +
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_matrix_operator {
|
||||
( $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) ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
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) ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
( $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) ); +
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
@ -1,281 +1,20 @@
|
||||
#[cfg(feature="fixed_wide_traits")]
|
||||
pub mod wide;
|
||||
|
||||
// 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 ), +
|
||||
}
|
||||
}
|
||||
|
||||
/// 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() ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
fn neg(self) -> Self::Output {
|
||||
Self {
|
||||
$( $field: -self.$field ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 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
|
||||
$crate::impl_wide_operations!( $struct { $($field), + }, $size );
|
||||
};
|
||||
}
|
||||
#[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! 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;
|
||||
|
||||
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;
|
||||
|
||||
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) ); +
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: core::ops::$trait + Copy> core::ops::$trait<T> for $struct<T> {
|
||||
fn $method(&mut self, other: T) {
|
||||
$( self.$field.$method(other) ); +
|
||||
}
|
||||
}
|
||||
};
|
||||
macro_rules! macro_repeated{
|
||||
(
|
||||
$macro:ident,
|
||||
$any:tt,
|
||||
$($repeated:tt),*
|
||||
)=>{
|
||||
$(
|
||||
$crate::$macro!($any, $repeated);
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
146
fixed_wide_vectors/src/macros/vector.rs
Normal file
146
fixed_wide_vectors/src/macros/vector.rs
Normal file
@ -0,0 +1,146 @@
|
||||
// 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), + }, $size: expr ) => {
|
||||
$crate::impl_common!($struct { $($field), + }, $size);
|
||||
|
||||
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 $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 )|| +
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: core::ops::Neg<Output = T>> core::ops::Neg for $struct<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn neg(self) -> Self::Output {
|
||||
Self {
|
||||
$( $field: -self.$field ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Impl arithmetic pperators
|
||||
$crate::impl_vector_operator!( $struct { $($field), + }, AddAssign, add_assign );
|
||||
$crate::impl_vector_operator!( $struct { $($field), + }, Add, add, Self );
|
||||
$crate::impl_vector_operator!( $struct { $($field), + }, SubAssign, sub_assign );
|
||||
$crate::impl_vector_operator!( $struct { $($field), + }, Sub, sub, Self );
|
||||
$crate::impl_vector_operator!( $struct { $($field), + }, MulAssign, mul_assign );
|
||||
$crate::impl_vector_operator!( $struct { $($field), + }, Mul, mul, Self );
|
||||
$crate::impl_vector_operator!( $struct { $($field), + }, DivAssign, div_assign );
|
||||
$crate::impl_vector_operator!( $struct { $($field), + }, Div, div, Self );
|
||||
$crate::impl_vector_operator!( $struct { $($field), + }, RemAssign, rem_assign );
|
||||
$crate::impl_vector_operator!( $struct { $($field), + }, Rem, rem, Self );
|
||||
|
||||
// Impl bitwise operators
|
||||
$crate::impl_vector_operator!( $struct { $($field), + }, BitAndAssign, bitand_assign );
|
||||
$crate::impl_vector_operator!( $struct { $($field), + }, BitAnd, bitand, Self );
|
||||
$crate::impl_vector_operator!( $struct { $($field), + }, BitOrAssign, bitor_assign );
|
||||
$crate::impl_vector_operator!( $struct { $($field), + }, BitOr, bitor, Self );
|
||||
$crate::impl_vector_operator!( $struct { $($field), + }, BitXorAssign, bitxor_assign );
|
||||
$crate::impl_vector_operator!( $struct { $($field), + }, BitXor, bitxor, Self );
|
||||
|
||||
// Impl floating-point based methods
|
||||
#[cfg(feature="fixed_wide")]
|
||||
$crate::impl_wide_vector_operations!( $struct { $($field), + }, $size );
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_extend {
|
||||
( $struct: ident { $($field: ident), + }, $struct_extended: ident, $field_extended: ident ) => {
|
||||
impl<T> $struct<T> {
|
||||
#[inline(always)]
|
||||
pub fn extend(self,value:T) -> $struct_extended<T> {
|
||||
$struct_extended {
|
||||
$( $field:self.$field, ) +
|
||||
$field_extended:value
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_vector_operator {
|
||||
( $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) ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
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) ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
( $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) ); +
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
#[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> {
|
||||
type Output=$struct<U>;
|
||||
#[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 ) +
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// 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) *
|
||||
};
|
||||
}
|
36
fixed_wide_vectors/src/matrix.rs
Normal file
36
fixed_wide_vectors/src/matrix.rs
Normal file
@ -0,0 +1,36 @@
|
||||
use crate::{Vector2,Vector3,Vector4};
|
||||
|
||||
pub struct Matrix2<T> {
|
||||
pub x_axis: T,
|
||||
pub y_axis: T,
|
||||
}
|
||||
pub struct Matrix3<T> {
|
||||
pub x_axis: T,
|
||||
pub y_axis: T,
|
||||
pub z_axis: T,
|
||||
}
|
||||
pub struct Matrix4<T> {
|
||||
pub x_axis: T,
|
||||
pub y_axis: T,
|
||||
pub z_axis: T,
|
||||
pub w_axis: 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_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)
|
||||
)
|
||||
);
|
63
fixed_wide_vectors/src/tests/fixed_wide.rs
Normal file
63
fixed_wide_vectors/src/tests/fixed_wide.rs
Normal file
@ -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,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")]
|
||||
mod fixed_wide;
|
||||
|
1
fixed_wide_vectors/src/tests/tests.rs
Normal file
1
fixed_wide_vectors/src/tests/tests.rs
Normal file
@ -0,0 +1 @@
|
||||
|
@ -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,13 +56,26 @@ 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,
|
||||
}
|
||||
|
||||
|
||||
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_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) );
|
||||
|
Reference in New Issue
Block a user