use crate::fixed::Fixed; use crate::ratio::Ratio; use typenum::{Sum,Unsigned}; use arrayvec::ArrayVec; use std::cmp::Ordering; macro_rules! impl_zeroes{ ($n:expr)=>{ impl Fixed<$n,F> where F:Unsigned+std::ops::Add, ::Output:Unsigned, { #[inline] pub fn zeroes2(a0:Self,a1:Self,a2:Self)->ArrayVec,2>{ let a2pos=match a2.cmp(&Self::ZERO){ Ordering::Greater=>true, Ordering::Equal=>return ArrayVec::from_iter($crate::zeroes::zeroes1(a0,a1).into_iter()), Ordering::Less=>true, }; let radicand=$crate::traits::WideMul::wide_mul(a1,a1)-$crate::traits::WideMul::wide_mul(a2,a0)*4; match radicand.cmp(&Fixed::<{$n*2},Sum>::ZERO){ Ordering::Greater=>{ //start with f64 sqrt //failure case: 2^63 < sqrt(2^127) let planar_radicand=radicand.sqrt(); //TODO: one or two newtons //sort roots ascending and avoid taking the difference of large numbers match (a2pos,Self::ZERO[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,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); impl_zeroes!(5); impl_zeroes!(6); impl_zeroes!(7); impl_zeroes!(8);