1use dashu_base::Sign;
2use dashu_int::{IBig, UBig};
3
4use crate::{
5 error::{assert_finite_operands, FpError, FpResult},
6 fbig::FBig,
7 helper_macros,
8 repr::{Context, Repr, Word},
9 round::Round,
10};
11use core::ops::{Mul, MulAssign};
12
13fn make_mul_repr<const B: Word>(lhs: &Repr<B>, rhs: &Repr<B>) -> Result<Repr<B>, FpError> {
18 let significand = &lhs.significand * &rhs.significand;
19 if significand.is_zero() {
20 return Ok(if lhs.sign() != rhs.sign() {
21 Repr::neg_zero()
22 } else {
23 Repr::zero()
24 });
25 }
26 let sign = if lhs.sign() != rhs.sign() {
27 Sign::Negative
28 } else {
29 Sign::Positive
30 };
31 let exponent = lhs.exponent.checked_add(rhs.exponent).ok_or_else(|| {
32 debug_assert!(
33 lhs.exponent.is_positive() == rhs.exponent.is_positive(),
34 "checked_add overflow with mixed-sign exponents is impossible"
35 );
36 if lhs.exponent > 0 {
37 FpError::Overflow(sign)
38 } else {
39 FpError::Underflow(sign)
40 }
41 })?;
42 Repr::new(significand, exponent).check_finite_exponent()
43}
44
45macro_rules! unwrap_mul_repr {
46 ($result:expr, $context:expr) => {
47 match $result {
48 Ok(r) => r,
49 Err(FpError::Overflow(sign)) => {
50 return FBig::new(Repr::infinity_with_sign(sign), $context);
51 }
52 Err(FpError::Underflow(sign)) => {
53 return FBig::new(Repr::zero_with_sign(sign), $context);
54 }
55 Err(_) => unreachable!(),
56 }
57 };
58}
59
60impl<R: Round, const B: Word> Mul<&FBig<R, B>> for &FBig<R, B> {
61 type Output = FBig<R, B>;
62
63 #[inline]
64 fn mul(self, rhs: &FBig<R, B>) -> Self::Output {
65 assert_finite_operands(&self.repr, &rhs.repr);
66
67 let context = Context::max(self.context, rhs.context);
68 let repr = unwrap_mul_repr!(make_mul_repr(&self.repr, &rhs.repr), context);
69 FBig::new(context.repr_round(repr).value(), context)
70 }
71}
72
73impl<R: Round, const B: Word> Mul<&FBig<R, B>> for FBig<R, B> {
74 type Output = FBig<R, B>;
75
76 #[inline]
77 fn mul(self, rhs: &FBig<R, B>) -> Self::Output {
78 assert_finite_operands(&self.repr, &rhs.repr);
79
80 let context = Context::max(self.context, rhs.context);
81 let repr = unwrap_mul_repr!(make_mul_repr(&self.repr, &rhs.repr), context);
82 FBig::new(context.repr_round(repr).value(), context)
83 }
84}
85
86impl<R: Round, const B: Word> Mul<FBig<R, B>> for &FBig<R, B> {
87 type Output = FBig<R, B>;
88
89 #[inline]
90 fn mul(self, rhs: FBig<R, B>) -> Self::Output {
91 assert_finite_operands(&self.repr, &rhs.repr);
92
93 let context = Context::max(self.context, rhs.context);
94 let repr = unwrap_mul_repr!(make_mul_repr(&self.repr, &rhs.repr), context);
95 FBig::new(context.repr_round(repr).value(), context)
96 }
97}
98
99impl<R: Round, const B: Word> Mul<FBig<R, B>> for FBig<R, B> {
100 type Output = FBig<R, B>;
101
102 #[inline]
103 fn mul(self, rhs: FBig<R, B>) -> Self::Output {
104 assert_finite_operands(&self.repr, &rhs.repr);
105
106 let context = Context::max(self.context, rhs.context);
107 let repr = unwrap_mul_repr!(make_mul_repr(&self.repr, &rhs.repr), context);
108 FBig::new(context.repr_round(repr).value(), context)
109 }
110}
111
112helper_macros::impl_binop_assign_by_taking!(impl MulAssign<Self>, mul_assign, mul);
113
114macro_rules! impl_mul_primitive_with_fbig {
115 ($($t:ty)*) => {$(
116 helper_macros::impl_binop_with_primitive!(impl Mul<$t>, mul);
117 helper_macros::impl_binop_assign_with_primitive!(impl MulAssign<$t>, mul_assign);
118 )*};
119}
120impl_mul_primitive_with_fbig!(u8 u16 u32 u64 u128 usize UBig i8 i16 i32 i64 i128 isize IBig);
121
122impl<R: Round, const B: Word> FBig<R, B> {
123 #[inline]
136 pub fn sqr(&self) -> Self {
137 self.context.unwrap_fp(self.context.sqr(&self.repr))
138 }
139
140 #[inline]
153 pub fn cubic(&self) -> Self {
154 self.context.unwrap_fp(self.context.cubic(&self.repr))
155 }
156}
157
158impl<R: Round> Context<R> {
159 pub fn mul<const B: Word>(&self, lhs: &Repr<B>, rhs: &Repr<B>) -> FpResult<FBig<R, B>> {
180 if lhs.is_infinite() || rhs.is_infinite() {
181 return Err(FpError::InfiniteInput);
182 }
183
184 let max_precision = if self.is_limited() {
187 self.precision * 2
188 } else {
189 usize::MAX
190 };
191
192 let lhs_shrink;
193 let lhs_repr = if lhs.digits() > max_precision {
194 lhs_shrink = Context::<R>::new(max_precision).repr_round_ref(lhs).value();
195 &lhs_shrink
196 } else {
197 lhs
198 };
199
200 let rhs_shrink;
201 let rhs_repr = if rhs.digits() > max_precision {
202 rhs_shrink = Context::<R>::new(max_precision).repr_round_ref(rhs).value();
203 &rhs_shrink
204 } else {
205 rhs
206 };
207
208 let repr = make_mul_repr(lhs_repr, rhs_repr)?;
209 Ok(self.repr_round(repr).map(|v| FBig::new(v, *self)))
210 }
211
212 pub fn sqr<const B: Word>(&self, f: &Repr<B>) -> FpResult<FBig<R, B>> {
229 if f.is_infinite() {
230 return Err(FpError::InfiniteInput);
231 }
232
233 let max_precision = if self.is_limited() {
235 self.precision * 2
236 } else {
237 usize::MAX
238 };
239
240 let f_shrink;
241 let f_repr = if f.digits() > max_precision {
242 f_shrink = Context::<R>::new(max_precision).repr_round_ref(f).value();
243 &f_shrink
244 } else {
245 f
246 };
247
248 let exponent = f_repr.exponent.checked_mul(2).ok_or({
249 if f_repr.exponent > 0 {
251 FpError::Overflow(Sign::Positive)
252 } else {
253 FpError::Underflow(Sign::Positive)
254 }
255 })?;
256 let repr = Repr::new(f_repr.significand.sqr().into(), exponent);
257 let repr = repr.check_finite_exponent()?;
258 Ok(self.repr_round(repr).map(|v| FBig::new(v, *self)))
259 }
260
261 pub fn cubic<const B: Word>(&self, f: &Repr<B>) -> FpResult<FBig<R, B>> {
278 if f.is_infinite() {
279 return Err(FpError::InfiniteInput);
280 }
281
282 let max_precision = if self.is_limited() {
284 self.precision * 3
285 } else {
286 usize::MAX
287 };
288
289 let f_shrink;
290 let f_repr = if f.digits() > max_precision {
291 f_shrink = Context::<R>::new(max_precision).repr_round_ref(f).value();
292 &f_shrink
293 } else {
294 f
295 };
296
297 let repr = if f_repr.significand.is_zero() {
298 if f_repr.is_neg_zero() {
300 Repr::neg_zero()
301 } else {
302 Repr::zero()
303 }
304 } else {
305 let sign = f_repr.sign();
306 let exponent = f_repr.exponent.checked_mul(3).ok_or({
307 if f_repr.exponent > 0 {
308 FpError::Overflow(sign)
309 } else {
310 FpError::Underflow(sign)
311 }
312 })?;
313 let repr = Repr::new(f_repr.significand.cubic(), exponent);
314 repr.check_finite_exponent()?
315 };
316 Ok(self.repr_round(repr).map(|v| FBig::new(v, *self)))
317 }
318}