5 Commits

Author SHA1 Message Date
33b335f987 what if do like this - wait idk 2024-08-28 14:09:44 -07:00
c9b999b8a6 can't get rid of the double pattern match not knowing which repeated variable to loop 2024-08-28 13:49:56 -07:00
23a6ffb243 wip transpose 2024-08-28 13:49:56 -07:00
9ef9b5ff3f traits 2024-08-28 13:49:56 -07:00
c277c31f29 wip 2024-08-28 13:49:56 -07:00
14 changed files with 140 additions and 589 deletions

View File

@@ -2,35 +2,13 @@
# 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"

View File

@@ -9,6 +9,3 @@ 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" }

View File

@@ -1,5 +1,3 @@
use std::ops::Mul;
#[derive(Clone,Copy,Debug,Hash)]
pub struct Ratio<Num,Den>{
pub(crate)num:Num,
@@ -10,163 +8,3 @@ impl<Num,Den> Ratio<Num,Den>{
Self{num,den}
}
}
impl<Num,Den,Rhs> PartialEq<Rhs> for Ratio<Num,Den>
where
Den:Copy,
Rhs:Mul<Den>+Copy,
Num:PartialEq<<Rhs as Mul<Den>>::Output>
{
fn eq(&self,rhs:&Rhs)->bool{
self.num.eq(&rhs.mul(self.den))
}
}
/*
//You can't do Ratio==Ratio I guess
impl<Num,Den> Eq for Ratio<Num,Den>
where
Num:Mul<Den>,
<Num as Mul<Den>>::Output:PartialEq
{}
*/
// num/den == rhs
// num == rhs * den
impl<Num,Den,Rhs> PartialOrd<Rhs> for Ratio<Num,Den>
where
Den:Copy,
Rhs:Mul<Den>+Copy,
Num:PartialOrd<<Rhs as Mul<Den>>::Output>
{
fn partial_cmp(&self,rhs:&Rhs)->Option<std::cmp::Ordering>{
self.num.partial_cmp(&rhs.mul(self.den))
}
}
/*
impl<Den,Rhs> Ord for Ratio<<Rhs as Mul<Den>>::Output,Den>
where
Rhs:Mul<Den>,
Rhs:Ord,
<Rhs as Mul<Den>>::Output:Ord,
{
fn cmp(&self,other:&Rhs)->std::cmp::Ordering{
self.num.cmp(&other.mul(self.den))
}
}
*/
impl<NewNum,Num:std::ops::Neg<Output=NewNum>,Den> std::ops::Neg for Ratio<Num,Den>{
type Output=Ratio<NewNum,Den>;
fn neg(self)->Self::Output{
Ratio{
num:self.num.neg(),
den:self.den,
}
}
}
// num/den + rhs == new_num/den
// new_num = num + rhs * den
macro_rules! impl_operator {
($struct:ident,$trait:ident,$method:ident)=>{
impl<Num,Den,Rhs> core::ops::$trait<Rhs> for $struct<Num,Den>
where
Den:Copy,
Rhs:Mul<Den>,
Num:core::ops::$trait<<Rhs as Mul<Den>>::Output>,
{
type Output=$struct<<Num as core::ops::$trait<<Rhs as Mul<Den>>::Output>>::Output,Den>;
fn $method(self,rhs:Rhs)->Self::Output{
$struct{
num:self.num.$method(rhs.mul(self.den)),
den:self.den,
}
}
}
impl<Num,Den,Lhs> core::ops::$trait<$struct<Num,Den>> for Lhs
where
Den:Copy,
Lhs:Mul<Den>,
<Lhs as Mul<Den>>::Output:core::ops::$trait<Num>,
{
type Output=$struct<<<Lhs as Mul<Den>>::Output as core::ops::$trait<Num>>::Output,Den>;
fn $method(self,rhs:$struct<Num,Den>)->Self::Output{
$struct{
num:self.mul(rhs.den).$method(rhs.num),
den:rhs.den,
}
}
}
};
}
macro_rules! impl_assign_operator{
($struct:ident,$trait:ident,$method:ident)=>{
impl<Num,Den,Rhs> core::ops::$trait<Rhs> for $struct<Num,Den>
where
Den:Copy,
Rhs:Mul<Den>,
Num:core::ops::$trait<<Rhs as Mul<Den>>::Output>,
{
fn $method(&mut self,rhs:Rhs){
self.num.$method(rhs.mul(self.den));
}
}
};
}
// Impl arithmetic operators
impl_assign_operator!(Ratio,AddAssign,add_assign);
impl_operator!(Ratio,Add,add);
impl_assign_operator!(Ratio,SubAssign,sub_assign);
impl_operator!(Ratio,Sub,sub);
// num/den % rhs == new_num/den
// new_num = num % (rhs * den)
impl_assign_operator!(Ratio,RemAssign,rem_assign);
impl_operator!(Ratio,Rem,rem);
//mul and div is special
impl<Num,Den,Rhs> Mul<Rhs> for Ratio<Num,Den>
where
Num:Mul<Rhs>,
{
type Output=Ratio<<Num as Mul<Rhs>>::Output,Den>;
fn mul(self,rhs:Rhs)->Self::Output{
Ratio{
num:self.num.mul(rhs),
den:self.den,
}
}
}
impl<Num,Den,Rhs> core::ops::MulAssign<Rhs> for Ratio<Num,Den>
where
Num:core::ops::MulAssign<Rhs>,
{
fn mul_assign(&mut self,rhs:Rhs){
self.num.mul_assign(rhs);
}
}
impl<Num,Den,Rhs> core::ops::Div<Rhs> for Ratio<Num,Den>
where
Den:Mul<Rhs>,
{
type Output=Ratio<Num,<Den as Mul<Rhs>>::Output>;
fn div(self,rhs:Rhs)->Self::Output{
Ratio{
num:self.num,
den:self.den.mul(rhs),
}
}
}
impl<Num,Den,Rhs> core::ops::DivAssign<Rhs> for Ratio<Num,Den>
where
Den:core::ops::MulAssign<Rhs>,
{
fn div_assign(&mut self,rhs:Rhs){
self.den.mul_assign(rhs);
}
}

View File

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

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -1,6 +1,6 @@
use std::ops::{Add,Mul};
use crate::ratio::Ratio;
use fixed_wide_traits::wide::{WideMul,WideDiv,WideDot,WideCross};
use fixed_wide_traits::wide::{WideMul,WideDiv};
impl<Num,Den:Copy> Ratio<Num,Den>
{
@@ -25,25 +25,18 @@ impl<Num,Den:Copy> Ratio<Num,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<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_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>,

View File

@@ -1,4 +1,4 @@
use bnum::{BInt,cast::As};
use bnum::BInt;
use typenum::Unsigned;
use std::marker::PhantomData;
@@ -9,26 +9,11 @@ pub struct Fixed<const CHUNKS:usize,Frac>{
}
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};
pub const MAX:Self=Self{bits:BInt::<CHUNKS>::MAX,frac:PhantomData};
pub const MIN:Self=Self{bits:BInt::<CHUNKS>::MIN,frac:PhantomData};
pub const ZERO:Self=Self{bits:BInt::<CHUNKS>::ZERO,frac:PhantomData};
pub const EPSILON:Self=Self{bits:BInt::<CHUNKS>::ONE,frac:PhantomData};
pub const NEG_EPSILON:Self=Self{bits:BInt::<CHUNKS>::NEG_ONE,frac:PhantomData};
pub const ONE:Self=Self{bits:BInt::<CHUNKS>::ONE.shl(Frac::U32),frac:PhantomData};
pub const TWO:Self=Self{bits:BInt::<CHUNKS>::TWO.shl(Frac::U32),frac:PhantomData};
pub const HALF:Self=Self{bits:BInt::<CHUNKS>::ONE.shl(Frac::U32-1),frac:PhantomData};
pub const NEG_ONE:Self=Self{bits:BInt::<CHUNKS>::NEG_ONE.shl(Frac::U32),frac:PhantomData};
pub const NEG_TWO:Self=Self{bits:BInt::<CHUNKS>::NEG_TWO.shl(Frac::U32),frac:PhantomData};
pub const NEG_HALF:Self=Self{bits:BInt::<CHUNKS>::NEG_ONE.shl(Frac::U32-1),frac:PhantomData};
pub const fn from_bits(bits:BInt::<CHUNKS>)->Self{
Self{
bits,
frac:PhantomData,
}
}
pub const fn to_bits(self)->BInt<CHUNKS>{
self.bits
}
}
impl<const CHUNKS:usize,Frac:Unsigned,T> From<T> for Fixed<CHUNKS,Frac>
@@ -71,224 +56,93 @@ impl<const CHUNKS:usize,Frac> std::ops::Neg for Fixed<CHUNKS,Frac>{
}
}
macro_rules! impl_additive_operator {
macro_rules! impl_operator {
( $struct: ident, $trait: ident, $method: ident, $output: ty ) => {
impl<const CHUNKS:usize,Frac> core::ops::$trait for $struct<CHUNKS,Frac>{
type Output = $output;
impl<const CHUNKS:usize,Frac> core::ops::$trait for $struct<CHUNKS,Frac>{
type Output = $output;
fn $method(self, other: Self) -> Self::Output {
Self {
bits:self.bits.$method(other.bits),
frac:PhantomData,
}
}
}
impl<const CHUNKS:usize,Frac:Unsigned,U> core::ops::$trait<U> for $struct<CHUNKS,Frac>
where
BInt::<CHUNKS>:From<U>,
{
type Output = $output;
fn $method(self, other: Self) -> Self::Output {
Self {
bits:self.bits.$method(other.bits),
frac:PhantomData,
}
}
}
impl<const CHUNKS:usize,Frac:Unsigned,U> core::ops::$trait<U> for $struct<CHUNKS,Frac>
where
BInt::<CHUNKS>:From<U>,
{
type Output = $output;
fn $method(self, other: U) -> Self::Output {
Self {
bits:self.bits.$method(BInt::<CHUNKS>::from(other)<<Frac::U32),
frac:PhantomData,
}
}
}
};
fn $method(self, other: U) -> Self::Output {
Self {
bits:self.bits.$method(BInt::<CHUNKS>::from(other)<<Frac::U32),
frac:PhantomData,
}
}
}
};
}
macro_rules! impl_additive_assign_operator {
( $struct: ident, $trait: ident, $method: ident ) => {
impl<const CHUNKS:usize,Frac> core::ops::$trait for $struct<CHUNKS,Frac>{
fn $method(&mut self, other: Self) {
self.bits.$method(other.bits);
}
}
impl<const CHUNKS:usize,Frac:Unsigned,U> core::ops::$trait<U> for $struct<CHUNKS,Frac>
where
BInt::<CHUNKS>:From<U>,
{
fn $method(&mut self, other: U) {
self.bits.$method(BInt::<CHUNKS>::from(other)<<Frac::U32);
}
}
};
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);
}
}
impl<const CHUNKS:usize,Frac:Unsigned,U> core::ops::$trait<U> for $struct<CHUNKS,Frac>
where
BInt::<CHUNKS>:From<U>,
{
fn $method(&mut self, other: U) {
self.bits.$method(BInt::<CHUNKS>::from(other)<<Frac::U32);
}
}
};
}
// Impl arithmetic pperators
impl_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_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 bitwise operators
impl_additive_assign_operator!( Fixed, BitAndAssign, bitand_assign );
impl_additive_operator!( Fixed, BitAnd, bitand, Self );
impl_additive_assign_operator!( Fixed, BitOrAssign, bitor_assign );
impl_additive_operator!( Fixed, BitOr, bitor, Self );
impl_additive_assign_operator!( Fixed, BitXorAssign, bitxor_assign );
impl_additive_operator!( Fixed, BitXor, bitxor, Self );
macro_rules! impl_multiply_operator_const {
( $width:expr, $struct: ident, $trait: ident, $method: ident, $output: ty ) => {
impl<Frac:Unsigned> core::ops::$trait for $struct<$width,Frac>{
type Output = $output;
fn $method(self, other: Self) -> Self::Output {
//this can be done better but that is a job for later
let lhs=self.bits.as_::<BInt::<{$width*2}>>();
let rhs=other.bits.as_::<BInt::<{$width*2}>>();
Self {
bits:lhs.mul(rhs).shr(Frac::U32).as_(),
frac:PhantomData,
}
}
}
};
}
macro_rules! impl_multiply_assign_operator_const {
( $width:expr, $struct: ident, $trait: ident, $method: ident ) => {
impl<Frac> core::ops::$trait for $struct<$width,Frac>{
fn $method(&mut self, other: Self) {
self.bits.$method(other.bits);
}
}
};
}
macro_rules! impl_divide_operator_const {
( $width:expr, $struct: ident, $trait: ident, $method: ident, $output: ty ) => {
impl<Frac:Unsigned> core::ops::$trait for $struct<$width,Frac>{
type Output = $output;
fn $method(self, other: Self) -> Self::Output {
//this can be done better but that is a job for later
//this only needs to be $width+Frac::U32/64+1 but MUH CONST GENERICS!!!!!
let lhs=self.bits.as_::<BInt::<{$width*2}>>().shl(Frac::U32);
let rhs=other.bits.as_::<BInt::<{$width*2}>>();
Self {
bits:lhs.div(rhs).as_(),
frac:PhantomData,
}
}
}
};
}
macro_rules! impl_divide_assign_operator_const {
( $width:expr, $struct: ident, $trait: ident, $method: ident ) => {
impl<Frac> core::ops::$trait for $struct<$width,Frac>{
fn $method(&mut self, other: Self) {
self.bits.$method(other.bits);
}
}
};
}
macro_rules! impl_multiplicatave_operator {
( $struct: ident, $trait: ident, $method: ident, $output: ty ) => {
impl<const CHUNKS:usize,Frac,U> core::ops::$trait<U> for $struct<CHUNKS,Frac>
where
BInt::<CHUNKS>:From<U>+core::ops::$trait,
{
type Output = $output;
fn $method(self, other: U) -> Self::Output {
Self {
bits:self.bits.$method(BInt::<CHUNKS>::from(other)),
frac:PhantomData,
}
}
}
};
}
macro_rules! impl_multiplicatave_assign_operator {
( $struct: ident, $trait: ident, $method: ident ) => {
impl<const CHUNKS:usize,Frac,U> core::ops::$trait<U> for $struct<CHUNKS,Frac>
where
BInt::<CHUNKS>:From<U>+core::ops::$trait,
{
fn $method(&mut self, other: U) {
self.bits.$method(BInt::<CHUNKS>::from(other));
}
}
};
}
macro_rules! impl_operator_16 {
( $macro: ident, $struct: ident, $trait: ident, $method: ident, $output: ty ) => {
$macro!(1,$struct,$trait,$method,$output);
$macro!(2,$struct,$trait,$method,$output);
$macro!(3,$struct,$trait,$method,$output);
$macro!(4,$struct,$trait,$method,$output);
$macro!(5,$struct,$trait,$method,$output);
$macro!(6,$struct,$trait,$method,$output);
$macro!(7,$struct,$trait,$method,$output);
$macro!(8,$struct,$trait,$method,$output);
$macro!(9,$struct,$trait,$method,$output);
$macro!(10,$struct,$trait,$method,$output);
$macro!(11,$struct,$trait,$method,$output);
$macro!(12,$struct,$trait,$method,$output);
$macro!(13,$struct,$trait,$method,$output);
$macro!(14,$struct,$trait,$method,$output);
$macro!(15,$struct,$trait,$method,$output);
$macro!(16,$struct,$trait,$method,$output);
}
}
macro_rules! impl_assign_operator_16 {
( $macro: ident, $struct: ident, $trait: ident, $method: ident ) => {
$macro!(1,$struct,$trait,$method);
$macro!(2,$struct,$trait,$method);
$macro!(3,$struct,$trait,$method);
$macro!(4,$struct,$trait,$method);
$macro!(5,$struct,$trait,$method);
$macro!(6,$struct,$trait,$method);
$macro!(7,$struct,$trait,$method);
$macro!(8,$struct,$trait,$method);
$macro!(9,$struct,$trait,$method);
$macro!(10,$struct,$trait,$method);
$macro!(11,$struct,$trait,$method);
$macro!(12,$struct,$trait,$method);
$macro!(13,$struct,$trait,$method);
$macro!(14,$struct,$trait,$method);
$macro!(15,$struct,$trait,$method);
$macro!(16,$struct,$trait,$method);
}
}
impl_assign_operator_16!( impl_multiply_assign_operator_const, Fixed, MulAssign, mul_assign );
impl_operator_16!( impl_multiply_operator_const, Fixed, Mul, mul, Self );
impl_assign_operator_16!( impl_divide_assign_operator_const, Fixed, DivAssign, div_assign );
impl_operator_16!( impl_divide_operator_const, Fixed, Div, div, Self );
impl_multiplicatave_assign_operator!( Fixed, MulAssign, mul_assign );
impl_multiplicatave_operator!( Fixed, Mul, mul, Self );
impl_multiplicatave_assign_operator!( Fixed, DivAssign, div_assign );
impl_multiplicatave_operator!( Fixed, Div, div, Self );
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 );
macro_rules! impl_shift_operator {
( $struct: ident, $trait: ident, $method: ident, $output: ty ) => {
impl<const CHUNKS:usize,Frac> core::ops::$trait<u32> for $struct<CHUNKS,Frac>{
type Output = $output;
impl<const CHUNKS:usize,Frac> core::ops::$trait<u32> for $struct<CHUNKS,Frac>{
type Output = $output;
fn $method(self, other: u32) -> Self::Output {
Self {
bits:self.bits.$method(other),
frac:PhantomData,
}
}
}
};
fn $method(self, other: u32) -> Self::Output {
Self {
bits:self.bits.$method(other),
frac:PhantomData,
}
}
}
};
}
macro_rules! impl_shift_assign_operator {
( $struct: ident, $trait: ident, $method: ident ) => {
impl<const CHUNKS:usize,Frac> core::ops::$trait<u32> for $struct<CHUNKS,Frac>{
fn $method(&mut self, other: u32) {
self.bits.$method(other);
}
}
};
( $struct: ident, $trait: ident, $method: ident ) => {
impl<const CHUNKS:usize,Frac> core::ops::$trait<u32> for $struct<CHUNKS,Frac>{
fn $method(&mut self, other: u32) {
self.bits.$method(other);
}
}
};
}
impl_shift_assign_operator!( Fixed, ShlAssign, shl_assign );
impl_shift_operator!( Fixed, Shl, shl, Self );

View File

@@ -24,11 +24,11 @@ macro_rules! impl_wide_mul {
}
macro_rules! impl_wide_mul_all {
($(($x:expr, $y:expr)),*) => {
$(
impl_wide_mul!($x, $y);
)*
};
($(($x:expr, $y:expr)),*) => {
$(
impl_wide_mul!($x, $y);
)*
};
}
//const generics sidestepped wahoo
@@ -42,70 +42,3 @@ impl_wide_mul_all!(
(1,7),(2,7),(3,7),(4,7),(5,7),(6,7),(7,7),(8,7),
(1,8),(2,8),(3,8),(4,8),(5,8),(6,8),(7,8),(8,8)
);
impl<const SRC:usize,Frac> Fixed<SRC,Frac>{
pub fn widen<const DST:usize>(self)->Fixed<DST,Frac>{
Fixed{
bits:self.bits.as_::<BInt<DST>>(),
frac:PhantomData,
}
}
}
impl<const CHUNKS:usize,Frac:Unsigned> Fixed<CHUNKS,Frac>
where
Fixed::<CHUNKS,Frac>:WideMul,
<Fixed::<CHUNKS,Frac> as WideMul>::Output:Ord,
{
pub fn sqrt_unchecked(self)->Self{
//pow2 must be the minimum power of two which when squared is greater than self
//the algorithm:
//1. count "used" bits to the left of the decimal
//2. add one
//This is the power of two which is greater than self.
//3. divide by 2 via >>1
//4. add on fractional offset
//Voila
//0001.0000 Fixed<u8,4>
//sqrt
//0110.0000
//pow2 = 0100.0000
let mut pow2=Self{
bits:BInt::<CHUNKS>::ONE.shl(((((CHUNKS as i32*64-Frac::I32-(self.bits.leading_zeros() as i32)+1)>>1)+Frac::I32) as u32).saturating_sub(1)),
frac:PhantomData,
};
let mut result=pow2;
//cheat to make the types match
let wide_self=self.wide_mul(Fixed::<CHUNKS,Frac>::ONE);
loop{
//TODO: closed loop over bit shift exponent rather than pow2
if pow2==Self::ZERO{
break result;
}
//TODO: flip a single bit instead of adding a power of 2
let new_result=result+pow2;
//note that the implicit truncation in the multiply
//means that the algorithm can return a result which squares to a number greater than the input.
match wide_self.cmp(&new_result.wide_mul(new_result)){
core::cmp::Ordering::Less=>(),
core::cmp::Ordering::Equal=>break new_result,
core::cmp::Ordering::Greater=>result=new_result,
}
pow2>>=1;
}
}
pub fn sqrt(self)->Self{
if self<Self::ZERO{
panic!("Square root less than zero")
}else{
self.sqrt_unchecked()
}
}
pub fn sqrt_checked(self)->Option<Self>{
if self<Self::ZERO{
None
}else{
Some(self.sqrt_unchecked())
}
}
}

View File

@@ -1,61 +1,14 @@
use fixed_wide_traits::wide::WideMul;
use crate::types::I32F32;
#[test]
fn test_wide_mul(){
let a=I32F32::ONE;
let a=crate::types::I32F32::ONE;
let aa=a.wide_mul(a);
assert_eq!(aa,crate::types::I64F64::ONE);
}
#[test]
fn test_bint(){
let a=I32F32::ONE;
assert_eq!(a*2,I32F32::from(2));
}
#[test]
fn test_sqrt(){
let a=I32F32::ONE*4;
assert_eq!(a.sqrt(),I32F32::from(2));
}
#[test]
fn test_sqrt_low(){
let a=I32F32::HALF;
let b=a*a;
assert_eq!(b.sqrt(),a);
}
fn find_equiv_sqrt_via_f64(n:I32F32)->I32F32{
//GIMME THEM BITS BOY
let &[bits]=n.to_bits().to_bits().digits();
let ibits=bits as i64;
let f=(ibits as f64)/((1u64<<32) as f64);
let f_ans=f.sqrt();
let i=(f_ans*((1u64<<32) as f64)) as i64;
let r=I32F32::from_bits(bnum::BInt::<1>::from(i));
//mimic the behaviour of the algorithm,
//return the result if it truncates to the exact answer
if (r+I32F32::EPSILON).wide_mul(r+I32F32::EPSILON)==n.wide_mul(I32F32::ONE){
return r+I32F32::EPSILON;
}
if (r-I32F32::EPSILON).wide_mul(r-I32F32::EPSILON)==n.wide_mul(I32F32::ONE){
return r-I32F32::EPSILON;
}
return r;
}
fn test_exact(n:I32F32){
assert_eq!(n.sqrt(),find_equiv_sqrt_via_f64(n));
}
#[test]
fn test_sqrt_exact(){
//43
for i in 0..((i64::MAX as f32).ln() as u32){
let n=I32F32::from_bits(bnum::BInt::<1>::from((i as f32).exp() as i64));
test_exact(n);
}
}
#[test]
fn test_sqrt_max(){
let a=I32F32::MAX;
test_exact(a);
let a=crate::types::I32F32::ONE;
assert_eq!(a*2,crate::types::I32F32::from(2));
}

View File

@@ -1,4 +1,5 @@
mod macros;
mod traits;
mod vector;
#[cfg(feature="fixed_wide_traits")]

View File

@@ -251,6 +251,38 @@ macro_rules! impl_vector {
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_inner {
( $struct_outer: ident { $($field_outer: ident), + }, $size_outer: expr,
$field_inner: ident) => {
$struct_outer {
$(
$field_outer: self.$field_outer.$field_inner
),+
}
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix {
( $struct_outer: ident { $($field_outer: ident),+ }, $size_outer: expr) => {
impl<T> Transpose for $struct_outer<$struct_inner<T>> {
fn transpose(self) -> $struct_inner<$struct_outer<T>> {
$struct_inner {
$(
$field_inner: impl_matrix_inner!(
Vector2{x,y}, $size_outer,
$field_inner
)
),+
}
}
}
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_operator {

View File

@@ -0,0 +1,8 @@
pub trait Dot<Rhs=Self>{
type Output;
fn dot(self,rhs:Rhs)->Self::Output;
}
pub trait Transpose{
type Output;
fn transpose(self)->Self::Output;
}

View File

@@ -66,3 +66,8 @@ 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);
//This internally implements non square matrices, idk how else to separate the repeated fields
crate::impl_matrix!(Vector2 { x, y }, 2);
crate::impl_matrix!(Vector3 { x, y, z }, 3);
crate::impl_matrix!(Vector4 { x, y, z, w }, 4);