1use crate::cbig::CBig;
4use crate::repr::{combine_parts, exact, riemann, CfpResult, Context};
5use core::ops::{Mul, MulAssign};
6use dashu_float::round::Round;
7use dashu_float::{FBig, FpError};
8use dashu_int::Word;
9
10const MUL_GUARD: usize = 10;
14
15impl<R: Round> Context<R> {
16 pub fn sqr<const B: Word>(&self, z: &CBig<R, B>) -> CfpResult<R, B> {
18 if z.is_infinite() {
19 return Ok(riemann(*self)); }
21 if z.is_zero() {
22 return Ok(exact(FBig::ZERO, FBig::ZERO));
23 }
24 let gctx = self.guard(MUL_GUARD);
25 let p = self.precision();
26 let (x, y) = (z.re(), z.im());
27 let x2 = gctx.sqr(x)?.value();
29 let y2 = gctx.sqr(y)?.value();
30 let re = gctx.sub(x2.repr(), y2.repr())?.value().with_precision(p);
31 let xy = gctx.mul(x, y)?.value();
33 let im = gctx.add(xy.repr(), xy.repr())?.value().with_precision(p);
34 Ok(combine_parts(re, im))
35 }
36
37 pub fn mul<const B: Word>(&self, z: &CBig<R, B>, w: &CBig<R, B>) -> CfpResult<R, B> {
40 if z.is_infinite() || w.is_infinite() {
41 if z.is_zero() || w.is_zero() {
42 return Err(FpError::Indeterminate); }
44 return Ok(riemann(Context::max(z.context(), w.context()))); }
46 let gctx = self.guard(MUL_GUARD);
47 let p = self.precision();
48 let (x, y) = (z.re(), z.im());
49 let (u, v) = (w.re(), w.im());
50 let xu = gctx.mul(x, u)?.value();
52 let yv = gctx.mul(y, v)?.value();
53 let re = gctx.sub(xu.repr(), yv.repr())?.value().with_precision(p);
54 let xv = gctx.mul(x, v)?.value();
56 let yu = gctx.mul(y, u)?.value();
57 let im = gctx.add(xv.repr(), yu.repr())?.value().with_precision(p);
58 Ok(combine_parts(re, im))
59 }
60
61 pub fn mul_real<const B: Word>(&self, z: &CBig<R, B>, s: &FBig<R, B>) -> CfpResult<R, B> {
63 if z.is_infinite() || s.repr().is_infinite() {
64 if z.is_zero() || s.repr().is_pos_zero() || s.repr().is_neg_zero() {
65 return Err(FpError::Indeterminate); }
67 return Ok(riemann(*self));
68 }
69 let gctx = self.guard(MUL_GUARD);
70 let p = self.precision();
71 let re = gctx.mul(z.re(), s.repr())?.value().with_precision(p);
72 let im = gctx.mul(z.im(), s.repr())?.value().with_precision(p);
73 Ok(combine_parts(re, im))
74 }
75}
76
77impl<R: Round, const B: Word> CBig<R, B> {
78 #[inline]
80 pub fn sqr(&self) -> Self {
81 self.context().unwrap_cfp(self.context().sqr(self))
82 }
83}
84
85crate::helper_macros::impl_cbig_binop!(Mul, mul, MulAssign, mul_assign);
87
88crate::helper_macros::impl_cbig_scalar_binop!(Mul, mul, mul_real);
92
93impl<R: Round, const B: Word> Mul<&CBig<R, B>> for &FBig<R, B> {
95 type Output = CBig<R, B>;
96 #[inline]
97 fn mul(self, rhs: &CBig<R, B>) -> CBig<R, B> {
98 rhs * self
99 }
100}
101impl<R: Round, const B: Word> Mul<CBig<R, B>> for &FBig<R, B> {
102 type Output = CBig<R, B>;
103 #[inline]
104 fn mul(self, rhs: CBig<R, B>) -> CBig<R, B> {
105 &rhs * self
106 }
107}
108impl<R: Round, const B: Word> Mul<&CBig<R, B>> for FBig<R, B> {
109 type Output = CBig<R, B>;
110 #[inline]
111 fn mul(self, rhs: &CBig<R, B>) -> CBig<R, B> {
112 rhs * &self
113 }
114}
115impl<R: Round, const B: Word> Mul<CBig<R, B>> for FBig<R, B> {
116 type Output = CBig<R, B>;
117 #[inline]
118 fn mul(self, rhs: CBig<R, B>) -> CBig<R, B> {
119 &rhs * &self
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126 use dashu_float::round::mode;
127
128 type C = CBig<mode::HalfAway, 10>;
129 type F = FBig<mode::HalfAway, 10>;
130
131 fn c(re: i32, im: i32) -> C {
132 let mk = |v: i32| -> F { F::from(v).with_precision(53).value() };
133 C::from_parts(mk(re), mk(im))
134 }
135
136 #[test]
137 fn sqr_basic() {
138 let z = c(3, 4);
140 let s = z.sqr();
141 assert_eq!(s.re().significand(), &(-7i32).into());
142 assert_eq!(s.im().significand(), &24.into());
143 }
144
145 #[test]
146 fn mul_basic() {
147 let z = c(1, 2);
149 let w = c(3, 4);
150 let p = &z * &w;
151 assert!(p == c(-5, 10));
152 }
153
154 #[test]
155 fn mul_assign_val_and_ref() {
156 let z = c(1, 2);
157 let w = c(3, 4);
158 let mut acc = z.clone();
160 acc *= w.clone();
161 assert!(acc == c(-5, 10));
162 let mut acc = z.clone();
163 acc *= &w;
164 assert!(acc == c(-5, 10));
165 }
166
167 #[test]
168 fn mul_by_one_is_identity() {
169 let z = c(3, 4);
170 let p = &z * &CBig::ONE;
171 assert!(p == z);
172 }
173
174 #[test]
175 fn mul_by_conj_is_norm() {
176 let z = c(3, 4);
178 let p = &z * &z.conj();
179 assert!(p.im().is_pos_zero() || p.im().is_neg_zero());
180 assert_eq!(p.re().significand(), &25.into());
181 }
182
183 #[test]
184 fn scalar_mul_by_real() {
185 let z = c(3, 4);
186 let s = FBig::<mode::HalfAway, 10>::from(2);
187 let p = &z * &s;
188 assert_eq!(p.re().significand(), &6.into());
189 assert_eq!(p.im().significand(), &8.into());
190 let p2 = &s * &z;
192 assert_eq!(p2.re().significand(), &6.into());
193 }
194}