dashu_float/
mul.rs

1use dashu_int::{IBig, UBig};
2
3use crate::{
4    error::{assert_finite, assert_finite_operands},
5    fbig::FBig,
6    helper_macros,
7    repr::{Context, Repr, Word},
8    round::{Round, Rounded},
9};
10use core::ops::{Mul, MulAssign};
11
12impl<'l, 'r, R: Round, const B: Word> Mul<&'r FBig<R, B>> for &'l FBig<R, B> {
13    type Output = FBig<R, B>;
14
15    #[inline]
16    fn mul(self, rhs: &FBig<R, B>) -> Self::Output {
17        assert_finite_operands(&self.repr, &rhs.repr);
18
19        let context = Context::max(self.context, rhs.context);
20        let repr = Repr::new(
21            &self.repr.significand * &rhs.repr.significand,
22            self.repr.exponent + rhs.repr.exponent,
23        );
24        FBig::new(context.repr_round(repr).value(), context)
25    }
26}
27
28impl<'r, R: Round, const B: Word> Mul<&'r FBig<R, B>> for FBig<R, B> {
29    type Output = FBig<R, B>;
30
31    #[inline]
32    fn mul(self, rhs: &FBig<R, B>) -> Self::Output {
33        assert_finite_operands(&self.repr, &rhs.repr);
34
35        let context = Context::max(self.context, rhs.context);
36        let repr = Repr::new(
37            self.repr.significand * &rhs.repr.significand,
38            self.repr.exponent + rhs.repr.exponent,
39        );
40        FBig::new(context.repr_round(repr).value(), context)
41    }
42}
43
44impl<'l, R: Round, const B: Word> Mul<FBig<R, B>> for &'l FBig<R, B> {
45    type Output = FBig<R, B>;
46
47    #[inline]
48    fn mul(self, rhs: FBig<R, B>) -> Self::Output {
49        assert_finite_operands(&self.repr, &rhs.repr);
50
51        let context = Context::max(self.context, rhs.context);
52        let repr = Repr::new(
53            &self.repr.significand * rhs.repr.significand,
54            self.repr.exponent + rhs.repr.exponent,
55        );
56        FBig::new(context.repr_round(repr).value(), context)
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 = Repr::new(
69            self.repr.significand * rhs.repr.significand,
70            self.repr.exponent + rhs.repr.exponent,
71        );
72        FBig::new(context.repr_round(repr).value(), context)
73    }
74}
75
76helper_macros::impl_binop_assign_by_taking!(impl MulAssign<Self>, mul_assign, mul);
77
78macro_rules! impl_mul_primitive_with_fbig {
79    ($($t:ty)*) => {$(
80        helper_macros::impl_binop_with_primitive!(impl Mul<$t>, mul);
81        helper_macros::impl_binop_assign_with_primitive!(impl MulAssign<$t>, mul_assign);
82    )*};
83}
84impl_mul_primitive_with_fbig!(u8 u16 u32 u64 u128 usize UBig i8 i16 i32 i64 i128 isize IBig);
85
86impl<R: Round, const B: Word> FBig<R, B> {
87    /// Compute the square of this number (`self * self`)
88    ///
89    /// # Examples
90    ///
91    /// ```
92    /// # use core::str::FromStr;
93    /// # use dashu_base::ParseError;
94    /// # use dashu_float::DBig;
95    /// let a = DBig::from_str("-1.234")?;
96    /// assert_eq!(a.sqr(), DBig::from_str("1.523")?);
97    /// # Ok::<(), ParseError>(())
98    /// ```
99    #[inline]
100    pub fn sqr(&self) -> Self {
101        self.context.sqr(&self.repr).value()
102    }
103
104    /// Compute the cubic of this number (`self * self * self`)
105    ///
106    /// # Examples
107    ///
108    /// ```
109    /// # use core::str::FromStr;
110    /// # use dashu_base::ParseError;
111    /// # use dashu_float::DBig;
112    /// let a = DBig::from_str("-1.234")?;
113    /// assert_eq!(a.cubic(), DBig::from_str("-1.879")?);
114    /// # Ok::<(), ParseError>(())
115    /// ```
116    #[inline]
117    pub fn cubic(&self) -> Self {
118        self.context.cubic(&self.repr).value()
119    }
120}
121
122impl<R: Round> Context<R> {
123    /// Multiply two floating point numbers under this context.
124    ///
125    /// # Examples
126    ///
127    /// ```
128    /// # use core::str::FromStr;
129    /// # use dashu_base::ParseError;
130    /// # use dashu_float::DBig;
131    /// use dashu_base::Approximation::*;
132    /// use dashu_float::{Context, round::{mode::HalfAway, Rounding::*}};
133    ///
134    /// let context = Context::<HalfAway>::new(2);
135    /// let a = DBig::from_str("-1.234")?;
136    /// let b = DBig::from_str("6.789")?;
137    /// assert_eq!(
138    ///     context.mul(&a.repr(), &b.repr()),
139    ///     Inexact(DBig::from_str("-8.4")?, SubOne)
140    /// );
141    /// # Ok::<(), ParseError>(())
142    /// ```
143    pub fn mul<const B: Word>(&self, lhs: &Repr<B>, rhs: &Repr<B>) -> Rounded<FBig<R, B>> {
144        assert_finite_operands(lhs, rhs);
145
146        // at most double the precision is required to get a correct result
147        // shrink the input operands if necessary
148        let max_precision = if self.is_limited() {
149            self.precision * 2
150        } else {
151            usize::MAX
152        };
153
154        let lhs_shrink;
155        let lhs_repr = if lhs.digits() > max_precision {
156            lhs_shrink = Context::<R>::new(max_precision).repr_round_ref(lhs).value();
157            &lhs_shrink
158        } else {
159            lhs
160        };
161
162        let rhs_shrink;
163        let rhs_repr = if rhs.digits() > max_precision {
164            rhs_shrink = Context::<R>::new(max_precision).repr_round_ref(rhs).value();
165            &rhs_shrink
166        } else {
167            rhs
168        };
169
170        let repr = Repr::new(
171            &lhs_repr.significand * &rhs_repr.significand,
172            lhs_repr.exponent + rhs_repr.exponent,
173        );
174        self.repr_round(repr).map(|v| FBig::new(v, *self))
175    }
176
177    /// Calculate the square of the floating point number under this context.
178    ///
179    /// # Examples
180    ///
181    /// ```
182    /// # use core::str::FromStr;
183    /// # use dashu_base::ParseError;
184    /// # use dashu_float::DBig;
185    /// use dashu_base::Approximation::*;
186    /// use dashu_float::{Context, round::{mode::HalfAway, Rounding::*}};
187    ///
188    /// let context = Context::<HalfAway>::new(2);
189    /// let a = DBig::from_str("-1.234")?;
190    /// assert_eq!(context.sqr(&a.repr()), Inexact(DBig::from_str("1.5")?, NoOp));
191    /// # Ok::<(), ParseError>(())
192    /// ```
193    pub fn sqr<const B: Word>(&self, f: &Repr<B>) -> Rounded<FBig<R, B>> {
194        assert_finite(f);
195
196        // shrink the input operands if necessary
197        let max_precision = if self.is_limited() {
198            self.precision * 2
199        } else {
200            usize::MAX
201        };
202
203        let f_shrink;
204        let f_repr = if f.digits() > max_precision {
205            f_shrink = Context::<R>::new(max_precision).repr_round_ref(f).value();
206            &f_shrink
207        } else {
208            f
209        };
210
211        let repr = Repr::new(f_repr.significand.sqr().into(), 2 * f_repr.exponent);
212        self.repr_round(repr).map(|v| FBig::new(v, *self))
213    }
214
215    /// Calculate the cubic of the floating point number under this context.
216    ///
217    /// # Examples
218    ///
219    /// ```
220    /// # use core::str::FromStr;
221    /// # use dashu_base::ParseError;
222    /// # use dashu_float::DBig;
223    /// use dashu_base::Approximation::*;
224    /// use dashu_float::{Context, round::{mode::HalfAway, Rounding::*}};
225    ///
226    /// let context = Context::<HalfAway>::new(2);
227    /// let a = DBig::from_str("-1.234")?;
228    /// assert_eq!(context.cubic(&a.repr()), Inexact(DBig::from_str("-1.9")?, SubOne));
229    /// # Ok::<(), ParseError>(())
230    /// ```
231    pub fn cubic<const B: Word>(&self, f: &Repr<B>) -> Rounded<FBig<R, B>> {
232        assert_finite(f);
233
234        // shrink the input operands if necessary
235        let max_precision = if self.is_limited() {
236            self.precision * 3
237        } else {
238            usize::MAX
239        };
240
241        let f_shrink;
242        let f_repr = if f.digits() > max_precision {
243            f_shrink = Context::<R>::new(max_precision).repr_round_ref(f).value();
244            &f_shrink
245        } else {
246            f
247        };
248
249        let repr = Repr::new(f_repr.significand.cubic(), 3 * f_repr.exponent);
250        self.repr_round(repr).map(|v| FBig::new(v, *self))
251    }
252}