Compare commits
3 Commits
from_float
...
width-conv
| Author | SHA1 | Date | |
|---|---|---|---|
| b57879dead | |||
| a274b6d232 | |||
| 218a7fbf0f |
@@ -197,6 +197,34 @@ macro_rules! impl_into_float {
|
||||
impl_into_float!(f32,u32,8,24);
|
||||
impl_into_float!(f64,u64,11,53);
|
||||
|
||||
#[inline]
|
||||
fn integer_decode_f32(f: f32) -> (u64, i16, bool) {
|
||||
let bits: u32 = f.to_bits();
|
||||
let sign: bool = bits & (1<<31) != 0;
|
||||
let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
|
||||
let mantissa = if exponent == 0 {
|
||||
(bits & 0x7fffff) << 1
|
||||
} else {
|
||||
(bits & 0x7fffff) | 0x800000
|
||||
};
|
||||
// Exponent bias + mantissa shift
|
||||
exponent -= 127 + 23;
|
||||
(mantissa as u64, exponent, sign)
|
||||
}
|
||||
#[inline]
|
||||
fn integer_decode_f64(f: f64) -> (u64, i16, bool) {
|
||||
let bits: u64 = f.to_bits();
|
||||
let sign: bool = bits & (1u64<<63) != 0;
|
||||
let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
|
||||
let mantissa = if exponent == 0 {
|
||||
(bits & 0xfffffffffffff) << 1
|
||||
} else {
|
||||
(bits & 0xfffffffffffff) | 0x10000000000000
|
||||
};
|
||||
// Exponent bias + mantissa shift
|
||||
exponent -= 1023 + 52;
|
||||
(mantissa, exponent, sign)
|
||||
}
|
||||
#[derive(Debug,Eq,PartialEq)]
|
||||
pub enum FixedFromFloatError{
|
||||
Nan,
|
||||
@@ -212,19 +240,13 @@ impl FixedFromFloatError{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct FloatInfo{
|
||||
sign:bool,
|
||||
digit_index:usize,
|
||||
bits:[u64;2],
|
||||
}
|
||||
|
||||
macro_rules! impl_from_float {
|
||||
( $input: ty, $unsigned: ty, $exponent_bits:expr, $mantissa_bits:expr, $exp_bias:expr ) => {
|
||||
( $decode:ident, $input: ty, $mantissa_bits:expr ) => {
|
||||
impl<const N:usize,const F:usize> TryFrom<$input> for Fixed<N,F>{
|
||||
type Error=FixedFromFloatError;
|
||||
#[inline]
|
||||
fn try_from(value:$input)->Result<Self,Self::Error>{
|
||||
const DIGIT_SHIFT:u32=6;
|
||||
match value.classify(){
|
||||
std::num::FpCategory::Nan=>Err(FixedFromFloatError::Nan),
|
||||
std::num::FpCategory::Infinite=>Err(FixedFromFloatError::Infinite),
|
||||
@@ -232,54 +254,27 @@ macro_rules! impl_from_float {
|
||||
std::num::FpCategory::Subnormal
|
||||
|std::num::FpCategory::Normal
|
||||
=>{
|
||||
fn to_float_info<const F:usize>(f:$input)->Option<FloatInfo>{
|
||||
const DIGIT_SHIFT:u32=6;
|
||||
let bits=f.to_bits();
|
||||
//extract exponent, add fractional offset
|
||||
//usize is used to calculate digit_index. exp_cycle must be at least 8 bits so 32 bits is fine
|
||||
let exp=((bits>>($mantissa_bits-1)) as usize&((1<<$exponent_bits)-1))+F;
|
||||
//if it's less than zero, that's a conversion underflow.
|
||||
let exp_bias=exp.checked_sub($exp_bias)?;
|
||||
//cycle the exponent to keep the top bit of the mantissa within the hi digit
|
||||
let exp_cycle=exp_bias.rem_euclid(64).overflowing_add($exp_bias+64).0;
|
||||
let out_bits=
|
||||
bits
|
||||
//remove (mask) sign bit and exponent
|
||||
&((1 as $unsigned<<($mantissa_bits-1))-1)
|
||||
//write exponent
|
||||
|((exp_cycle as $unsigned)<<($mantissa_bits-1));
|
||||
//ready to convert
|
||||
let _128=<$input>::from_bits(out_bits) as u128;
|
||||
Some(FloatInfo{
|
||||
sign:f.is_sign_negative(),
|
||||
//digit_index is where the hi digit should end up in a fixed point number
|
||||
digit_index:exp_bias>>DIGIT_SHIFT,
|
||||
bits:[_128 as u64,(_128>>64) as u64],
|
||||
})
|
||||
}
|
||||
|
||||
let FloatInfo{
|
||||
sign,
|
||||
digit_index,
|
||||
bits:[lo,hi],
|
||||
}=to_float_info::<F>(value)
|
||||
.ok_or(FixedFromFloatError::Underflow)?;
|
||||
|
||||
let (m,e,s)=$decode(value);
|
||||
let mut digits=[0u64;N];
|
||||
let digit=digits.get_mut(digit_index)
|
||||
.ok_or(FixedFromFloatError::Overflow)?;
|
||||
*digit=hi;
|
||||
|
||||
if digit_index!=0{
|
||||
//if digit_index exists, so does digit_index-1
|
||||
digits[digit_index-1]=lo;
|
||||
let most_significant_bit=e as i32+$mantissa_bits as i32+F as i32;
|
||||
if most_significant_bit<0{
|
||||
return Err(FixedFromFloatError::Underflow);
|
||||
}
|
||||
let digit_index=most_significant_bit>>DIGIT_SHIFT;
|
||||
let digit=digits.get_mut(digit_index as usize).ok_or(FixedFromFloatError::Overflow)?;
|
||||
let take_bits=most_significant_bit-(digit_index<<DIGIT_SHIFT);
|
||||
let rest_of_mantissa=-($mantissa_bits as i32-(take_bits as i32));
|
||||
*digit=signed_shift(m,rest_of_mantissa);
|
||||
if rest_of_mantissa<0&&digit_index!=0{
|
||||
//we don't care if some float bits are partially truncated
|
||||
if let Some(digit)=digits.get_mut((digit_index-1) as usize){
|
||||
let take_bits=most_significant_bit-((digit_index-1)<<DIGIT_SHIFT);
|
||||
let rest_of_mantissa=-($mantissa_bits as i32-(take_bits as i32));
|
||||
*digit=signed_shift(m,rest_of_mantissa);
|
||||
}
|
||||
}
|
||||
|
||||
let bits=BInt::from_bits(bnum::BUint::from_digits(digits));
|
||||
if bits.is_negative()&&!(sign&&bits==BInt::MIN){
|
||||
return Err(FixedFromFloatError::Overflow);
|
||||
}
|
||||
Ok(if sign{
|
||||
Ok(if s{
|
||||
Self::from_bits(bits.overflowing_neg().0)
|
||||
}else{
|
||||
Self::from_bits(bits)
|
||||
@@ -290,8 +285,8 @@ macro_rules! impl_from_float {
|
||||
}
|
||||
}
|
||||
}
|
||||
impl_from_float!(f32,u32,8,24,127);
|
||||
impl_from_float!(f64,u64,11,53,1023);
|
||||
impl_from_float!(integer_decode_f32,f32,24);
|
||||
impl_from_float!(integer_decode_f64,f64,53);
|
||||
|
||||
impl<const N:usize,const F:usize> core::fmt::Display for Fixed<N,F>{
|
||||
#[inline]
|
||||
@@ -675,74 +670,94 @@ macro_repeated!(
|
||||
1,2,3,4,5,6,7,8
|
||||
);
|
||||
|
||||
pub trait Fix<Out>{
|
||||
fn fix(self)->Out;
|
||||
#[derive(Debug,Eq,PartialEq)]
|
||||
pub enum NarrowError{
|
||||
Overflow,
|
||||
Underflow,
|
||||
}
|
||||
|
||||
macro_rules! impl_fix_rhs_lt_lhs_not_const_generic{
|
||||
pub trait Wrap<Output>{
|
||||
fn wrap(self)->Output;
|
||||
}
|
||||
pub trait Clamp<Output>{
|
||||
fn clamp(self)->Output;
|
||||
}
|
||||
impl<const N:usize,const F:usize> Clamp<Fixed<N,F>> for Result<Fixed<N,F>,NarrowError>{
|
||||
fn clamp(self)->Fixed<N,F>{
|
||||
match self{
|
||||
Ok(fixed)=>fixed,
|
||||
Err(NarrowError::Overflow)=>Fixed::MAX,
|
||||
Err(NarrowError::Underflow)=>Fixed::MIN,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_narrow_not_const_generic{
|
||||
(
|
||||
(),
|
||||
($lhs:expr,$rhs:expr)
|
||||
)=>{
|
||||
impl Fixed<$lhs,{$lhs*32}>
|
||||
{
|
||||
paste::item!{
|
||||
paste::item!{
|
||||
impl Fixed<$lhs,{$lhs*32}>
|
||||
{
|
||||
#[inline]
|
||||
pub fn [<fix_ $rhs>](self)->Fixed<$rhs,{$rhs*32}>{
|
||||
pub fn [<wrap_ $rhs>](self)->Fixed<$rhs,{$rhs*32}>{
|
||||
Fixed::from_bits(bnum::cast::As::as_::<BInt::<$rhs>>(self.bits.shr(($lhs-$rhs)*32)))
|
||||
}
|
||||
#[inline]
|
||||
pub fn [<narrow_ $rhs>](self)->Result<Fixed<$rhs,{$rhs*32}>,NarrowError>{
|
||||
if Fixed::<$rhs,{$rhs*32}>::MAX.[<widen_ $lhs>]().bits<self.bits{
|
||||
return Err(NarrowError::Overflow);
|
||||
}
|
||||
if self.bits<Fixed::<$rhs,{$rhs*32}>::MIN.[<widen_ $lhs>]().bits{
|
||||
return Err(NarrowError::Underflow);
|
||||
}
|
||||
Ok(self.[<wrap_ $rhs>]())
|
||||
}
|
||||
#[inline]
|
||||
pub fn [<clamp_ $rhs>](self)->Fixed<$rhs,{$rhs*32}>{
|
||||
self.[<narrow_ $rhs>]().clamp()
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Fix<Fixed<$rhs,{$rhs*32}>> for Fixed<$lhs,{$lhs*32}>{
|
||||
fn fix(self)->Fixed<$rhs,{$rhs*32}>{
|
||||
paste::item!{
|
||||
self.[<fix_ $rhs>]()
|
||||
impl Wrap<Fixed<$rhs,{$rhs*32}>> for Fixed<$lhs,{$lhs*32}>{
|
||||
#[inline]
|
||||
fn wrap(self)->Fixed<$rhs,{$rhs*32}>{
|
||||
self.[<wrap_ $rhs>]()
|
||||
}
|
||||
}
|
||||
impl TryInto<Fixed<$rhs,{$rhs*32}>> for Fixed<$lhs,{$lhs*32}>{
|
||||
type Error=NarrowError;
|
||||
#[inline]
|
||||
fn try_into(self)->Result<Fixed<$rhs,{$rhs*32}>,Self::Error>{
|
||||
self.[<narrow_ $rhs>]()
|
||||
}
|
||||
}
|
||||
impl Clamp<Fixed<$rhs,{$rhs*32}>> for Fixed<$lhs,{$lhs*32}>{
|
||||
#[inline]
|
||||
fn clamp(self)->Fixed<$rhs,{$rhs*32}>{
|
||||
self.[<clamp_ $rhs>]()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
macro_rules! impl_fix_lhs_lt_rhs_not_const_generic{
|
||||
macro_rules! impl_widen_not_const_generic{
|
||||
(
|
||||
(),
|
||||
($lhs:expr,$rhs:expr)
|
||||
)=>{
|
||||
impl Fixed<$lhs,{$lhs*32}>
|
||||
{
|
||||
paste::item!{
|
||||
paste::item!{
|
||||
impl Fixed<$lhs,{$lhs*32}>
|
||||
{
|
||||
#[inline]
|
||||
pub fn [<fix_ $rhs>](self)->Fixed<$rhs,{$rhs*32}>{
|
||||
pub fn [<widen_ $rhs>](self)->Fixed<$rhs,{$rhs*32}>{
|
||||
Fixed::from_bits(bnum::cast::As::as_::<BInt::<$rhs>>(self.bits).shl(($rhs-$lhs)*32))
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Fix<Fixed<$rhs,{$rhs*32}>> for Fixed<$lhs,{$lhs*32}>{
|
||||
fn fix(self)->Fixed<$rhs,{$rhs*32}>{
|
||||
paste::item!{
|
||||
self.[<fix_ $rhs>]()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
macro_rules! impl_fix_lhs_eq_rhs_not_const_generic{
|
||||
(
|
||||
(),
|
||||
($lhs:expr,$rhs:expr)
|
||||
)=>{
|
||||
impl Fixed<$lhs,{$lhs*32}>
|
||||
{
|
||||
paste::item!{
|
||||
impl Into<Fixed<$rhs,{$rhs*32}>> for Fixed<$lhs,{$lhs*32}>{
|
||||
#[inline]
|
||||
pub fn [<fix_ $rhs>](self)->Fixed<$rhs,{$rhs*32}>{
|
||||
self
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Fix<Fixed<$rhs,{$rhs*32}>> for Fixed<$lhs,{$lhs*32}>{
|
||||
fn fix(self)->Fixed<$rhs,{$rhs*32}>{
|
||||
paste::item!{
|
||||
self.[<fix_ $rhs>]()
|
||||
fn into(self)->Fixed<$rhs,{$rhs*32}>{
|
||||
self.[<widen_ $rhs>]()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -752,7 +767,7 @@ macro_rules! impl_fix_lhs_eq_rhs_not_const_generic{
|
||||
// I LOVE NOT BEING ABLE TO USE CONST GENERICS
|
||||
|
||||
macro_repeated!(
|
||||
impl_fix_rhs_lt_lhs_not_const_generic,(),
|
||||
impl_narrow_not_const_generic,(),
|
||||
(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(9,1),(10,1),(11,1),(12,1),(13,1),(14,1),(15,1),(16,1),(17,1),
|
||||
(3,2),(4,2),(5,2),(6,2),(7,2),(8,2),(9,2),(10,2),(11,2),(12,2),(13,2),(14,2),(15,2),(16,2),
|
||||
(4,3),(5,3),(6,3),(7,3),(8,3),(9,3),(10,3),(11,3),(12,3),(13,3),(14,3),(15,3),(16,3),
|
||||
@@ -770,7 +785,7 @@ macro_repeated!(
|
||||
(16,15)
|
||||
);
|
||||
macro_repeated!(
|
||||
impl_fix_lhs_lt_rhs_not_const_generic,(),
|
||||
impl_widen_not_const_generic,(),
|
||||
(1,2),
|
||||
(1,3),(2,3),
|
||||
(1,4),(2,4),(3,4),
|
||||
@@ -785,11 +800,8 @@ macro_repeated!(
|
||||
(1,13),(2,13),(3,13),(4,13),(5,13),(6,13),(7,13),(8,13),(9,13),(10,13),(11,13),(12,13),
|
||||
(1,14),(2,14),(3,14),(4,14),(5,14),(6,14),(7,14),(8,14),(9,14),(10,14),(11,14),(12,14),(13,14),
|
||||
(1,15),(2,15),(3,15),(4,15),(5,15),(6,15),(7,15),(8,15),(9,15),(10,15),(11,15),(12,15),(13,15),(14,15),
|
||||
(1,16),(2,16),(3,16),(4,16),(5,16),(6,16),(7,16),(8,16),(9,16),(10,16),(11,16),(12,16),(13,16),(14,16),(15,16)
|
||||
);
|
||||
macro_repeated!(
|
||||
impl_fix_lhs_eq_rhs_not_const_generic,(),
|
||||
(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(10,10),(11,11),(12,12),(13,13),(14,14),(15,15),(16,16)
|
||||
(1,16),(2,16),(3,16),(4,16),(5,16),(6,16),(7,16),(8,16),(9,16),(10,16),(11,16),(12,16),(13,16),(14,16),(15,16),
|
||||
(1,17)
|
||||
);
|
||||
|
||||
macro_rules! impl_not_const_generic{
|
||||
@@ -809,7 +821,7 @@ macro_rules! impl_not_const_generic{
|
||||
let mut result=Self::ZERO;
|
||||
|
||||
//resize self to match the wide mul output
|
||||
let wide_self=self.[<fix_ $_2n>]();
|
||||
let wide_self=self.[<widen_ $_2n>]();
|
||||
//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={
|
||||
|
||||
@@ -47,8 +47,6 @@ fn from_f32(){
|
||||
assert_eq!(b,Ok(a));
|
||||
let a=I256F256::from(0);
|
||||
let b:Result<I256F256,_>=0.try_into();
|
||||
//test float mantissa spread across digit boundary
|
||||
//16 is within the 24 bits of float precision
|
||||
assert_eq!(b,Ok(a));
|
||||
let a=I256F256::from(0b101011110101001010101010000000000000000000000000000i64)<<16;
|
||||
let b:Result<I256F256,_>=(0b101011110101001010101010000000000000000000000000000u64 as f32*2.0f32.powi(16)).try_into();
|
||||
@@ -58,12 +56,12 @@ fn from_f32(){
|
||||
let b:Result<I32F32,_>=Into::<f32>::into(I32F32::MAX).try_into();
|
||||
assert_eq!(b,Ok(a));
|
||||
//I32F32::MIN hits a special case since it's not representable as a positive signed integer
|
||||
//TODO: don't return an overflow because this is technically possible
|
||||
let a=I32F32::MIN;
|
||||
let b:Result<I32F32,_>=Into::<f32>::into(I32F32::MIN).try_into();
|
||||
assert_eq!(b,Ok(a));
|
||||
let b:Result<I32F32,_>=Into::<f32>::into(I32F32::MIN.fix_2()+(I32F32::MIN>>1).fix_2()).try_into();
|
||||
assert_eq!(b,Err(crate::fixed::FixedFromFloatError::Overflow));
|
||||
let b:Result<I32F32,_>=Into::<f32>::into(-I32F32::MIN.fix_2()).try_into();
|
||||
//16 is within the 24 bits of float precision
|
||||
let b:Result<I32F32,_>=Into::<f32>::into(-I32F32::MIN.widen_2()).try_into();
|
||||
assert_eq!(b,Err(crate::fixed::FixedFromFloatError::Overflow));
|
||||
let b:Result<I32F32,_>=f32::MIN_POSITIVE.try_into();
|
||||
assert_eq!(b,Err(crate::fixed::FixedFromFloatError::Underflow));
|
||||
@@ -138,11 +136,24 @@ fn test_bint(){
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fix(){
|
||||
assert_eq!(I32F32::ONE.fix_8(),I256F256::ONE);
|
||||
assert_eq!(I32F32::ONE,I256F256::ONE.fix_1());
|
||||
assert_eq!(I32F32::NEG_ONE.fix_8(),I256F256::NEG_ONE);
|
||||
assert_eq!(I32F32::NEG_ONE,I256F256::NEG_ONE.fix_1());
|
||||
fn test_wrap(){
|
||||
assert_eq!(I32F32::ONE,I256F256::ONE.wrap_1());
|
||||
assert_eq!(I32F32::NEG_ONE,I256F256::NEG_ONE.wrap_1());
|
||||
}
|
||||
#[test]
|
||||
fn test_narrow(){
|
||||
assert_eq!(Ok(I32F32::ONE),I256F256::ONE.narrow_1());
|
||||
assert_eq!(Ok(I32F32::NEG_ONE),I256F256::NEG_ONE.narrow_1());
|
||||
}
|
||||
#[test]
|
||||
fn test_widen(){
|
||||
assert_eq!(I32F32::ONE.widen_8(),I256F256::ONE);
|
||||
assert_eq!(I32F32::NEG_ONE.widen_8(),I256F256::NEG_ONE);
|
||||
}
|
||||
#[test]
|
||||
fn test_clamp(){
|
||||
assert_eq!(I32F32::ONE,I256F256::ONE.clamp_1());
|
||||
assert_eq!(I32F32::NEG_ONE,I256F256::NEG_ONE.clamp_1());
|
||||
}
|
||||
#[test]
|
||||
fn test_sqrt(){
|
||||
|
||||
@@ -38,40 +38,95 @@ macro_rules! impl_fixed_wide_vector {
|
||||
$crate::macro_4!(impl_fixed_wide_vector_not_const_generic,());
|
||||
// I LOVE NOT BEING ABLE TO USE CONST GENERICS
|
||||
$crate::macro_repeated!(
|
||||
impl_fix_not_const_generic,(),
|
||||
(1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(9,1),(10,1),(11,1),(12,1),(13,1),(14,1),(15,1),(16,1),
|
||||
(1,2),(2,2),(3,2),(4,2),(5,2),(6,2),(7,2),(8,2),(9,2),(10,2),(11,2),(12,2),(13,2),(14,2),(15,2),(16,2),
|
||||
(1,3),(2,3),(3,3),(4,3),(5,3),(6,3),(7,3),(8,3),(9,3),(10,3),(11,3),(12,3),(13,3),(14,3),(15,3),(16,3),
|
||||
(1,4),(2,4),(3,4),(4,4),(5,4),(6,4),(7,4),(8,4),(9,4),(10,4),(11,4),(12,4),(13,4),(14,4),(15,4),(16,4),
|
||||
(1,5),(2,5),(3,5),(4,5),(5,5),(6,5),(7,5),(8,5),(9,5),(10,5),(11,5),(12,5),(13,5),(14,5),(15,5),(16,5),
|
||||
(1,6),(2,6),(3,6),(4,6),(5,6),(6,6),(7,6),(8,6),(9,6),(10,6),(11,6),(12,6),(13,6),(14,6),(15,6),(16,6),
|
||||
(1,7),(2,7),(3,7),(4,7),(5,7),(6,7),(7,7),(8,7),(9,7),(10,7),(11,7),(12,7),(13,7),(14,7),(15,7),(16,7),
|
||||
(1,8),(2,8),(3,8),(4,8),(5,8),(6,8),(7,8),(8,8),(9,8),(10,8),(11,8),(12,8),(13,8),(14,8),(15,8),(16,8),
|
||||
(1,9),(2,9),(3,9),(4,9),(5,9),(6,9),(7,9),(8,9),(9,9),(10,9),(11,9),(12,9),(13,9),(14,9),(15,9),(16,9),
|
||||
(1,10),(2,10),(3,10),(4,10),(5,10),(6,10),(7,10),(8,10),(9,10),(10,10),(11,10),(12,10),(13,10),(14,10),(15,10),(16,10),
|
||||
(1,11),(2,11),(3,11),(4,11),(5,11),(6,11),(7,11),(8,11),(9,11),(10,11),(11,11),(12,11),(13,11),(14,11),(15,11),(16,11),
|
||||
(1,12),(2,12),(3,12),(4,12),(5,12),(6,12),(7,12),(8,12),(9,12),(10,12),(11,12),(12,12),(13,12),(14,12),(15,12),(16,12),
|
||||
(1,13),(2,13),(3,13),(4,13),(5,13),(6,13),(7,13),(8,13),(9,13),(10,13),(11,13),(12,13),(13,13),(14,13),(15,13),(16,13),
|
||||
(1,14),(2,14),(3,14),(4,14),(5,14),(6,14),(7,14),(8,14),(9,14),(10,14),(11,14),(12,14),(13,14),(14,14),(15,14),(16,14),
|
||||
(1,15),(2,15),(3,15),(4,15),(5,15),(6,15),(7,15),(8,15),(9,15),(10,15),(11,15),(12,15),(13,15),(14,15),(15,15),(16,15),
|
||||
(1,16),(2,16),(3,16),(4,16),(5,16),(6,16),(7,16),(8,16),(9,16),(10,16),(11,16),(12,16),(13,16),(14,16),(15,16),(16,16)
|
||||
impl_narrow_not_const_generic,(),
|
||||
(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(9,1),(10,1),(11,1),(12,1),(13,1),(14,1),(15,1),(16,1),(17,1),
|
||||
(3,2),(4,2),(5,2),(6,2),(7,2),(8,2),(9,2),(10,2),(11,2),(12,2),(13,2),(14,2),(15,2),(16,2),
|
||||
(4,3),(5,3),(6,3),(7,3),(8,3),(9,3),(10,3),(11,3),(12,3),(13,3),(14,3),(15,3),(16,3),
|
||||
(5,4),(6,4),(7,4),(8,4),(9,4),(10,4),(11,4),(12,4),(13,4),(14,4),(15,4),(16,4),
|
||||
(6,5),(7,5),(8,5),(9,5),(10,5),(11,5),(12,5),(13,5),(14,5),(15,5),(16,5),
|
||||
(7,6),(8,6),(9,6),(10,6),(11,6),(12,6),(13,6),(14,6),(15,6),(16,6),
|
||||
(8,7),(9,7),(10,7),(11,7),(12,7),(13,7),(14,7),(15,7),(16,7),
|
||||
(9,8),(10,8),(11,8),(12,8),(13,8),(14,8),(15,8),(16,8),
|
||||
(10,9),(11,9),(12,9),(13,9),(14,9),(15,9),(16,9),
|
||||
(11,10),(12,10),(13,10),(14,10),(15,10),(16,10),
|
||||
(12,11),(13,11),(14,11),(15,11),(16,11),
|
||||
(13,12),(14,12),(15,12),(16,12),
|
||||
(14,13),(15,13),(16,13),
|
||||
(15,14),(16,14),
|
||||
(16,15)
|
||||
);
|
||||
$crate::macro_repeated!(
|
||||
impl_widen_not_const_generic,(),
|
||||
(1,2),
|
||||
(1,3),(2,3),
|
||||
(1,4),(2,4),(3,4),
|
||||
(1,5),(2,5),(3,5),(4,5),
|
||||
(1,6),(2,6),(3,6),(4,6),(5,6),
|
||||
(1,7),(2,7),(3,7),(4,7),(5,7),(6,7),
|
||||
(1,8),(2,8),(3,8),(4,8),(5,8),(6,8),(7,8),
|
||||
(1,9),(2,9),(3,9),(4,9),(5,9),(6,9),(7,9),(8,9),
|
||||
(1,10),(2,10),(3,10),(4,10),(5,10),(6,10),(7,10),(8,10),(9,10),
|
||||
(1,11),(2,11),(3,11),(4,11),(5,11),(6,11),(7,11),(8,11),(9,11),(10,11),
|
||||
(1,12),(2,12),(3,12),(4,12),(5,12),(6,12),(7,12),(8,12),(9,12),(10,12),(11,12),
|
||||
(1,13),(2,13),(3,13),(4,13),(5,13),(6,13),(7,13),(8,13),(9,13),(10,13),(11,13),(12,13),
|
||||
(1,14),(2,14),(3,14),(4,14),(5,14),(6,14),(7,14),(8,14),(9,14),(10,14),(11,14),(12,14),(13,14),
|
||||
(1,15),(2,15),(3,15),(4,15),(5,15),(6,15),(7,15),(8,15),(9,15),(10,15),(11,15),(12,15),(13,15),(14,15),
|
||||
(1,16),(2,16),(3,16),(4,16),(5,16),(6,16),(7,16),(8,16),(9,16),(10,16),(11,16),(12,16),(13,16),(14,16),(15,16),
|
||||
(1,17)
|
||||
);
|
||||
impl<const N:usize,T:fixed_wide::fixed::Wrap<U>,U> fixed_wide::fixed::Wrap<Vector<N,U>> for Vector<N,T>
|
||||
{
|
||||
#[inline]
|
||||
fn wrap(self)->Vector<N,U>{
|
||||
self.map(|t|t.wrap())
|
||||
}
|
||||
}
|
||||
impl<const N:usize,T:fixed_wide::fixed::Clamp<U>,U> fixed_wide::fixed::Clamp<Vector<N,U>> for Vector<N,T>
|
||||
{
|
||||
#[inline]
|
||||
fn clamp(self)->Vector<N,U>{
|
||||
self.map(|t|t.clamp())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_fix_not_const_generic{
|
||||
macro_rules! impl_narrow_not_const_generic{
|
||||
(
|
||||
(),
|
||||
($lhs:expr,$rhs:expr)
|
||||
)=>{
|
||||
impl<const N:usize> Vector<N,fixed_wide::fixed::Fixed<$lhs,{$lhs*32}>>
|
||||
{
|
||||
paste::item!{
|
||||
paste::item!{
|
||||
impl<const N:usize> Vector<N,fixed_wide::fixed::Fixed<$lhs,{$lhs*32}>>{
|
||||
#[inline]
|
||||
pub fn [<fix_ $rhs>](self)->Vector<N,fixed_wide::fixed::Fixed<$rhs,{$rhs*32}>>{
|
||||
self.map(|t|t.[<fix_ $rhs>]())
|
||||
pub fn [<wrap_ $rhs>](self)->Vector<N,fixed_wide::fixed::Fixed<$rhs,{$rhs*32}>>{
|
||||
self.map(|t|t.[<wrap_ $rhs>]())
|
||||
}
|
||||
#[inline]
|
||||
pub fn [<narrow_ $rhs>](self)->Vector<N,Result<fixed_wide::fixed::Fixed<$rhs,{$rhs*32}>,fixed_wide::fixed::NarrowError>>{
|
||||
self.map(|t|t.[<narrow_ $rhs>]())
|
||||
}
|
||||
#[inline]
|
||||
pub fn [<clamp_ $rhs>](self)->Vector<N,fixed_wide::fixed::Fixed<$rhs,{$rhs*32}>>{
|
||||
self.map(|t|t.[<clamp_ $rhs>]())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_widen_not_const_generic{
|
||||
(
|
||||
(),
|
||||
($lhs:expr,$rhs:expr)
|
||||
)=>{
|
||||
paste::item!{
|
||||
impl<const N:usize> Vector<N,fixed_wide::fixed::Fixed<$lhs,{$lhs*32}>>{
|
||||
#[inline]
|
||||
pub fn [<widen_ $rhs>](self)->Vector<N,fixed_wide::fixed::Fixed<$rhs,{$rhs*32}>>{
|
||||
self.map(|t|t.[<widen_ $rhs>]())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,32 +251,35 @@ impl_ratio_assign_operator!(RemAssign,rem_assign);
|
||||
// Only implement PartialEq<Self>
|
||||
// Rust's operators aren't actually that good
|
||||
|
||||
impl<Num,Den,T> PartialEq for Ratio<Num,Den>
|
||||
impl<LhsNum,LhsDen,RhsNum,RhsDen,T,U> PartialEq<Ratio<RhsNum,RhsDen>> for Ratio<LhsNum,LhsDen>
|
||||
where
|
||||
Num:Copy,
|
||||
Den:Copy,
|
||||
Num:core::ops::Mul<Den,Output=T>,
|
||||
T:PartialEq,
|
||||
LhsNum:Copy,
|
||||
LhsDen:Copy,
|
||||
RhsNum:Copy,
|
||||
RhsDen:Copy,
|
||||
LhsNum:core::ops::Mul<RhsDen,Output=T>,
|
||||
RhsNum:core::ops::Mul<LhsDen,Output=U>,
|
||||
T:PartialEq<U>,
|
||||
{
|
||||
#[inline]
|
||||
fn eq(&self,&other:&Self)->bool{
|
||||
fn eq(&self,other:&Ratio<RhsNum,RhsDen>)->bool{
|
||||
(self.num*other.den).eq(&(other.num*self.den))
|
||||
}
|
||||
}
|
||||
impl<Num,Den> Eq for Ratio<Num,Den>
|
||||
where
|
||||
Ratio<Num,Den>:PartialEq,
|
||||
{}
|
||||
impl<Num,Den> Eq for Ratio<Num,Den> where Self:PartialEq{}
|
||||
|
||||
impl<Num,Den,T> PartialOrd for Ratio<Num,Den>
|
||||
impl<LhsNum,LhsDen,RhsNum,RhsDen,T,U> PartialOrd<Ratio<RhsNum,RhsDen>> for Ratio<LhsNum,LhsDen>
|
||||
where
|
||||
Num:Copy,
|
||||
Den:Copy,
|
||||
Num:core::ops::Mul<Den,Output=T>,
|
||||
T:PartialOrd,
|
||||
LhsNum:Copy,
|
||||
LhsDen:Copy,
|
||||
RhsNum:Copy,
|
||||
RhsDen:Copy,
|
||||
LhsNum:core::ops::Mul<RhsDen,Output=T>,
|
||||
RhsNum:core::ops::Mul<LhsDen,Output=U>,
|
||||
T:PartialOrd<U>,
|
||||
{
|
||||
#[inline]
|
||||
fn partial_cmp(&self,&other:&Self)->Option<core::cmp::Ordering>{
|
||||
fn partial_cmp(&self,other:&Ratio<RhsNum,RhsDen>)->Option<core::cmp::Ordering>{
|
||||
(self.num*other.den).partial_cmp(&(other.num*self.den))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user