Skip to content

Commit 77e77f0

Browse files
committed
Implement Mul/Div/RemAssign directly
We can avoid a `self.clone()` by using more op-assign calls in place. Fixes rust-num#50.
1 parent f443e17 commit 77e77f0

File tree

1 file changed

+36
-25
lines changed

1 file changed

+36
-25
lines changed

src/lib.rs

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -731,18 +731,21 @@ impl<T: Clone + Num> Div<Complex<T>> for Complex<T> {
731731

732732
forward_all_binop!(impl Rem, rem);
733733

734-
// Attempts to identify the gaussian integer whose product with `modulus`
735-
// is closest to `self`.
734+
impl<T: Clone + Num> Complex<T> {
735+
/// Find the gaussian integer corresponding to the true ratio rounded towards zero.
736+
fn div_trunc(&self, divisor: &Self) -> Self {
737+
let Complex { re, im } = self / divisor;
738+
Complex::new(re.clone() - re % T::one(), im.clone() - im % T::one())
739+
}
740+
}
741+
736742
impl<T: Clone + Num> Rem<Complex<T>> for Complex<T> {
737743
type Output = Self;
738744

739745
#[inline]
740746
fn rem(self, modulus: Self) -> Self::Output {
741-
let Complex { re, im } = self.clone() / modulus.clone();
742-
// This is the gaussian integer corresponding to the true ratio
743-
// rounded towards zero.
744-
let (re0, im0) = (re.clone() - re % T::one(), im.clone() - im % T::one());
745-
self - modulus * Self::Output::new(re0, im0)
747+
let gaussian = self.div_trunc(&modulus);
748+
self - modulus * gaussian
746749
}
747750
}
748751

@@ -769,9 +772,16 @@ mod opassign {
769772
}
770773
}
771774

775+
// (a + i b) * (c + i d) == (a*c - b*d) + i (a*d + b*c)
772776
impl<T: Clone + NumAssign> MulAssign for Complex<T> {
773777
fn mul_assign(&mut self, other: Self) {
774-
*self = self.clone() * other;
778+
let a = self.re.clone();
779+
780+
self.re *= other.re.clone();
781+
self.re -= self.im.clone() * other.im.clone();
782+
783+
self.im *= other.re;
784+
self.im += a * other.im;
775785
}
776786
}
777787

@@ -797,15 +807,27 @@ mod opassign {
797807
}
798808
}
799809

810+
// (a + i b) / (c + i d) == [(a + i b) * (c - i d)] / (c*c + d*d)
811+
// == [(a*c + b*d) / (c*c + d*d)] + i [(b*c - a*d) / (c*c + d*d)]
800812
impl<T: Clone + NumAssign> DivAssign for Complex<T> {
801813
fn div_assign(&mut self, other: Self) {
802-
*self = self.clone() / other;
814+
let a = self.re.clone();
815+
let norm_sqr = other.norm_sqr();
816+
817+
self.re *= other.re.clone();
818+
self.re += self.im.clone() * other.im.clone();
819+
self.re /= norm_sqr.clone();
820+
821+
self.im *= other.re;
822+
self.im -= a * other.im;
823+
self.im /= norm_sqr;
803824
}
804825
}
805826

806827
impl<T: Clone + NumAssign> RemAssign for Complex<T> {
807-
fn rem_assign(&mut self, other: Self) {
808-
*self = self.clone() % other;
828+
fn rem_assign(&mut self, modulus: Self) {
829+
let gaussian = self.div_trunc(&modulus);
830+
*self -= modulus * gaussian;
809831
}
810832
}
811833

@@ -837,7 +859,8 @@ mod opassign {
837859

838860
impl<T: Clone + NumAssign> RemAssign<T> for Complex<T> {
839861
fn rem_assign(&mut self, other: T) {
840-
*self = self.clone() % other;
862+
self.re %= other.clone();
863+
self.im %= other;
841864
}
842865
}
843866

@@ -862,19 +885,7 @@ mod opassign {
862885
forward_op_assign!(impl SubAssign, sub_assign);
863886
forward_op_assign!(impl MulAssign, mul_assign);
864887
forward_op_assign!(impl DivAssign, div_assign);
865-
866-
impl<'a, T: Clone + NumAssign> RemAssign<&'a Complex<T>> for Complex<T> {
867-
#[inline]
868-
fn rem_assign(&mut self, other: &Self) {
869-
self.rem_assign(other.clone())
870-
}
871-
}
872-
impl<'a, T: Clone + NumAssign> RemAssign<&'a T> for Complex<T> {
873-
#[inline]
874-
fn rem_assign(&mut self, other: &T) {
875-
self.rem_assign(other.clone())
876-
}
877-
}
888+
forward_op_assign!(impl RemAssign, rem_assign);
878889
}
879890

880891
impl<T: Clone + Num + Neg<Output = T>> Neg for Complex<T> {

0 commit comments

Comments
 (0)