1 // Copyright © 2016–2020 University of Malta
2 
3 // This program is free software: you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public License
5 // as published by the Free Software Foundation, either version 3 of
6 // the License, or (at your option) any later version.
7 //
8 // This program is distributed in the hope that it will be useful, but
9 // WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License and a copy of the GNU General Public License along with
15 // this program. If not, see <https://www.gnu.org/licenses/>.
16 
17 #[cfg(feature = "integer")]
18 use crate::Integer;
19 #[cfg(feature = "rational")]
20 use crate::Rational;
21 use crate::{
22     ext::xmpfr::{self, OptFloat},
23     float::{Round, SmallFloat},
24     ops::{
25         AddAssignRound, AddFrom, AddFromRound, AssignRound, DivAssignRound, DivFrom, DivFromRound,
26         MulAssignRound, MulFrom, MulFromRound, NegAssign, Pow, PowAssign, PowAssignRound, PowFrom,
27         PowFromRound, RemAssignRound, RemFrom, RemFromRound, SubAssignRound, SubFrom, SubFromRound,
28     },
29     Float,
30 };
31 use az::{CheckedAs, CheckedCast};
32 use core::{
33     cmp::Ordering,
34     ops::{
35         Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Shl, ShlAssign, Shr,
36         ShrAssign, Sub, SubAssign,
37     },
38 };
39 use libc::{c_long, c_ulong};
40 
41 impl Neg for Float {
42     type Output = Float;
43     #[inline]
neg(mut self) -> Float44     fn neg(mut self) -> Float {
45         self.neg_assign();
46         self
47     }
48 }
49 
50 impl NegAssign for Float {
51     #[inline]
neg_assign(&mut self)52     fn neg_assign(&mut self) {
53         xmpfr::neg(self, (), Round::Nearest);
54     }
55 }
56 
57 impl<'a> Neg for &'a Float {
58     type Output = NegIncomplete<'a>;
59     #[inline]
neg(self) -> NegIncomplete<'a>60     fn neg(self) -> NegIncomplete<'a> {
61         NegIncomplete { val: self }
62     }
63 }
64 
65 #[derive(Debug)]
66 pub struct NegIncomplete<'a> {
67     val: &'a Float,
68 }
69 
70 impl AssignRound<NegIncomplete<'_>> for Float {
71     type Round = Round;
72     type Ordering = Ordering;
73     #[inline]
assign_round(&mut self, src: NegIncomplete<'_>, round: Round) -> Ordering74     fn assign_round(&mut self, src: NegIncomplete<'_>, round: Round) -> Ordering {
75         xmpfr::neg(self, src.val, round)
76     }
77 }
78 
79 arith_binary_self_round! {
80     Float, Round, Round::Nearest, Ordering;
81     xmpfr::add;
82     Add { add }
83     AddAssign { add_assign }
84     AddAssignRound { add_assign_round }
85     AddFrom { add_from }
86     AddFromRound { add_from_round }
87     AddIncomplete
88 }
89 arith_binary_self_round! {
90     Float, Round, Round::Nearest, Ordering;
91     xmpfr::sub;
92     Sub { sub }
93     SubAssign { sub_assign }
94     SubAssignRound { sub_assign_round }
95     SubFrom { sub_from }
96     SubFromRound { sub_from_round }
97     SubIncomplete
98 }
99 arith_binary_self_round! {
100     Float, Round, Round::Nearest, Ordering;
101     xmpfr::mul;
102     Mul { mul }
103     MulAssign { mul_assign }
104     MulAssignRound { mul_assign_round }
105     MulFrom { mul_from }
106     MulFromRound { mul_from_round }
107     MulIncomplete
108 }
109 arith_binary_self_round! {
110     Float, Round, Round::Nearest, Ordering;
111     xmpfr::div;
112     Div { div }
113     DivAssign { div_assign }
114     DivAssignRound { div_assign_round }
115     DivFrom { div_from }
116     DivFromRound { div_from_round }
117     DivIncomplete
118 }
119 arith_binary_self_round! {
120     Float, Round, Round::Nearest, Ordering;
121     xmpfr::fmod;
122     Rem { rem }
123     RemAssign { rem_assign }
124     RemAssignRound { rem_assign_round }
125     RemFrom { rem_from }
126     RemFromRound { rem_from_round }
127     RemIncomplete
128 }
129 arith_binary_self_round! {
130     Float, Round, Round::Nearest, Ordering;
131     xmpfr::pow;
132     Pow { pow }
133     PowAssign { pow_assign }
134     PowAssignRound { pow_assign_round }
135     PowFrom { pow_from }
136     PowFromRound { pow_from_round }
137     PowIncomplete
138 }
139 
140 #[cfg(feature = "integer")]
141 arith_commut_round! {
142     Float, Round, Round::Nearest, Ordering;
143     xmpfr::add_z;
144     Add { add }
145     AddAssign { add_assign }
146     AddAssignRound { add_assign_round }
147     AddFrom { add_from }
148     AddFromRound { add_from_round }
149     Integer;
150     AddIntegerIncomplete, AddOwnedIntegerIncomplete
151 }
152 #[cfg(feature = "integer")]
153 arith_noncommut_round! {
154     Float, Round, Round::Nearest, Ordering;
155     xmpfr::sub_z, xmpfr::z_sub;
156     Sub { sub }
157     SubAssign { sub_assign }
158     SubAssignRound { sub_assign_round }
159     SubFrom { sub_from }
160     SubFromRound { sub_from_round }
161     Integer;
162     SubIntegerIncomplete, SubOwnedIntegerIncomplete;
163     SubFromIntegerIncomplete, SubFromOwnedIntegerIncomplete
164 }
165 #[cfg(feature = "integer")]
166 arith_commut_round! {
167     Float, Round, Round::Nearest, Ordering;
168     xmpfr::mul_z;
169     Mul { mul }
170     MulAssign { mul_assign }
171     MulAssignRound { mul_assign_round }
172     MulFrom { mul_from }
173     MulFromRound { mul_from_round }
174     Integer;
175     MulIntegerIncomplete, MulOwnedIntegerIncomplete
176 }
177 #[cfg(feature = "integer")]
178 arith_noncommut_round! {
179     Float, Round, Round::Nearest, Ordering;
180     xmpfr::div_z, xmpfr::z_div;
181     Div { div }
182     DivAssign { div_assign }
183     DivAssignRound { div_assign_round }
184     DivFrom { div_from }
185     DivFromRound { div_from_round }
186     Integer;
187     DivIntegerIncomplete, DivOwnedIntegerIncomplete;
188     DivFromIntegerIncomplete, DivFromOwnedIntegerIncomplete
189 }
190 #[cfg(feature = "integer")]
191 arith_forward_round! {
192     Float, Round, Round::Nearest, Ordering;
193     xmpfr::pow_z;
194     Pow { pow }
195     PowAssign { pow_assign }
196     PowAssignRound { pow_assign_round }
197     Integer;
198     PowIntegerIncomplete, PowOwnedIntegerIncomplete
199 }
200 
201 #[cfg(feature = "rational")]
202 arith_commut_round! {
203     Float, Round, Round::Nearest, Ordering;
204     xmpfr::add_q;
205     Add { add }
206     AddAssign { add_assign }
207     AddAssignRound { add_assign_round }
208     AddFrom { add_from }
209     AddFromRound { add_from_round }
210     Rational;
211     AddRationalIncomplete, AddOwnedRationalIncomplete
212 }
213 #[cfg(feature = "rational")]
214 arith_noncommut_round! {
215     Float, Round, Round::Nearest, Ordering;
216     xmpfr::sub_q, xmpfr::q_sub;
217     Sub { sub }
218     SubAssign { sub_assign }
219     SubAssignRound { sub_assign_round }
220     SubFrom { sub_from }
221     SubFromRound { sub_from_round }
222     Rational;
223     SubRationalIncomplete, SubOwnedRationalIncomplete;
224     SubFromRationalIncomplete, SubFromOwnedRationalIncomplete
225 }
226 #[cfg(feature = "rational")]
227 arith_commut_round! {
228     Float, Round, Round::Nearest, Ordering;
229     xmpfr::mul_q;
230     Mul { mul }
231     MulAssign { mul_assign }
232     MulAssignRound { mul_assign_round }
233     MulFrom { mul_from }
234     MulFromRound { mul_from_round }
235     Rational;
236     MulRationalIncomplete, MulOwnedRationalIncomplete
237 }
238 #[cfg(feature = "rational")]
239 arith_noncommut_round! {
240     Float, Round, Round::Nearest, Ordering;
241     xmpfr::div_q, xmpfr::q_div;
242     Div { div }
243     DivAssign { div_assign }
244     DivAssignRound { div_assign_round }
245     DivFrom { div_from }
246     DivFromRound { div_from_round }
247     Rational;
248     DivRationalIncomplete, DivOwnedRationalIncomplete;
249     DivFromRationalIncomplete, DivFromOwnedRationalIncomplete
250 }
251 
252 arith_prim_commut_round! {
253     Float, Round, Round::Nearest, Ordering;
254     PrimOps::add;
255     Add { add }
256     AddAssign { add_assign }
257     AddAssignRound { add_assign_round }
258     AddFrom { add_from }
259     AddFromRound { add_from_round }
260     i8, AddI8Incomplete;
261     i16, AddI16Incomplete;
262     i32, AddI32Incomplete;
263     i64, AddI64Incomplete;
264     i128, AddI128Incomplete;
265     u8, AddU8Incomplete;
266     u16, AddU16Incomplete;
267     u32, AddU32Incomplete;
268     u64, AddU64Incomplete;
269     u128, AddU128Incomplete;
270     f32, AddF32Incomplete;
271     f64, AddF64Incomplete;
272 }
273 arith_prim_noncommut_round! {
274     Float, Round, Round::Nearest, Ordering;
275     PrimOps::sub, PrimOps::sub_from;
276     Sub { sub }
277     SubAssign { sub_assign }
278     SubAssignRound { sub_assign_round }
279     SubFrom { sub_from }
280     SubFromRound { sub_from_round }
281     i8, SubI8Incomplete, SubFromI8Incomplete;
282     i16, SubI16Incomplete, SubFromI16Incomplete;
283     i32, SubI32Incomplete, SubFromI32Incomplete;
284     i64, SubI64Incomplete, SubFromI64Incomplete;
285     i128, SubI128Incomplete, SubFromI128Incomplete;
286     u8, SubU8Incomplete, SubFromU8Incomplete;
287     u16, SubU16Incomplete, SubFromU16Incomplete;
288     u32, SubU32Incomplete, SubFromU32Incomplete;
289     u64, SubU64Incomplete, SubFromU64Incomplete;
290     u128, SubU128Incomplete, SubFromU128Incomplete;
291     f32, SubF32Incomplete, SubFromF32Incomplete;
292     f64, SubF64Incomplete, SubFromF64Incomplete;
293 }
294 arith_prim_commut_round! {
295     Float, Round, Round::Nearest, Ordering;
296     PrimOps::mul;
297     Mul { mul }
298     MulAssign { mul_assign }
299     MulAssignRound { mul_assign_round }
300     MulFrom { mul_from }
301     MulFromRound { mul_from_round }
302     i8, MulI8Incomplete;
303     i16, MulI16Incomplete;
304     i32, MulI32Incomplete;
305     i64, MulI64Incomplete;
306     i128, MulI128Incomplete;
307     u8, MulU8Incomplete;
308     u16, MulU16Incomplete;
309     u32, MulU32Incomplete;
310     u64, MulU64Incomplete;
311     u128, MulU128Incomplete;
312     f32, MulF32Incomplete;
313     f64, MulF64Incomplete;
314 }
315 arith_prim_noncommut_round! {
316     Float, Round, Round::Nearest, Ordering;
317     PrimOps::div, PrimOps::div_from;
318     Div { div }
319     DivAssign { div_assign }
320     DivAssignRound { div_assign_round }
321     DivFrom { div_from }
322     DivFromRound { div_from_round }
323     i8, DivI8Incomplete, DivFromI8Incomplete;
324     i16, DivI16Incomplete, DivFromI16Incomplete;
325     i32, DivI32Incomplete, DivFromI32Incomplete;
326     i64, DivI64Incomplete, DivFromI64Incomplete;
327     i128, DivI128Incomplete, DivFromI128Incomplete;
328     u8, DivU8Incomplete, DivFromU8Incomplete;
329     u16, DivU16Incomplete, DivFromU16Incomplete;
330     u32, DivU32Incomplete, DivFromU32Incomplete;
331     u64, DivU64Incomplete, DivFromU64Incomplete;
332     u128, DivU128Incomplete, DivFromU128Incomplete;
333     f32, DivF32Incomplete, DivFromF32Incomplete;
334     f64, DivF64Incomplete, DivFromF64Incomplete;
335 }
336 arith_prim_noncommut_round! {
337     Float, Round, Round::Nearest, Ordering;
338     PrimOps::rem, PrimOps::rem_from;
339     Rem { rem }
340     RemAssign { rem_assign }
341     RemAssignRound { rem_assign_round }
342     RemFrom { rem_from }
343     RemFromRound { rem_from_round }
344     i8, RemI8Incomplete, RemFromI8Incomplete;
345     i16, RemI16Incomplete, RemFromI16Incomplete;
346     i32, RemI32Incomplete, RemFromI32Incomplete;
347     i64, RemI64Incomplete, RemFromI64Incomplete;
348     i128, RemI128Incomplete, RemFromI128Incomplete;
349     u8, RemU8Incomplete, RemFromU8Incomplete;
350     u16, RemU16Incomplete, RemFromU16Incomplete;
351     u32, RemU32Incomplete, RemFromU32Incomplete;
352     u64, RemU64Incomplete, RemFromU64Incomplete;
353     u128, RemU128Incomplete, RemFromU128Incomplete;
354     f32, RemF32Incomplete, RemFromF32Incomplete;
355     f64, RemF64Incomplete, RemFromF64Incomplete;
356 }
357 arith_prim_noncommut_round! {
358     Float, Round, Round::Nearest, Ordering;
359     PrimOps::pow, PrimOps::pow_from;
360     Pow { pow }
361     PowAssign { pow_assign }
362     PowAssignRound { pow_assign_round }
363     PowFrom { pow_from }
364     PowFromRound { pow_from_round }
365     i8, PowI8Incomplete, PowFromI8Incomplete;
366     i16, PowI16Incomplete, PowFromI16Incomplete;
367     i32, PowI32Incomplete, PowFromI32Incomplete;
368     i64, PowI64Incomplete, PowFromI64Incomplete;
369     i128, PowI128Incomplete, PowFromI128Incomplete;
370     u8, PowU8Incomplete, PowFromU8Incomplete;
371     u16, PowU16Incomplete, PowFromU16Incomplete;
372     u32, PowU32Incomplete, PowFromU32Incomplete;
373     u64, PowU64Incomplete, PowFromU64Incomplete;
374     u128, PowU128Incomplete, PowFromU128Incomplete;
375     f32, PowF32Incomplete, PowFromF32Incomplete;
376     f64, PowF64Incomplete, PowFromF64Incomplete;
377 }
378 
379 arith_prim_exact_round! {
380     Float, Round, Round::Nearest, Ordering;
381     xmpfr::shl_u32;
382     Shl { shl }
383     ShlAssign { shl_assign }
384     u32, ShlU32Incomplete;
385 }
386 arith_prim_exact_round! {
387     Float, Round, Round::Nearest, Ordering;
388     xmpfr::shr_u32;
389     Shr { shr }
390     ShrAssign { shr_assign }
391     u32, ShrU32Incomplete;
392 }
393 arith_prim_exact_round! {
394     Float, Round, Round::Nearest, Ordering;
395     xmpfr::shl_i32;
396     Shl { shl }
397     ShlAssign { shl_assign }
398     i32, ShlI32Incomplete;
399 }
400 arith_prim_exact_round! {
401     Float, Round, Round::Nearest, Ordering;
402     xmpfr::shr_i32;
403     Shr { shr }
404     ShrAssign { shr_assign }
405     i32, ShrI32Incomplete;
406 }
407 mul_op_commut_round! {
408     Float, Round, Round::Nearest, Ordering;
409     add_mul;
410     Add { add }
411     AddAssign { add_assign }
412     AddAssignRound { add_assign_round }
413     AddFrom { add_from }
414     AddFromRound { add_from_round }
415     MulIncomplete;
416     AddMulIncomplete
417 }
418 mul_op_noncommut_round! {
419     Float, Round, Round::Nearest, Ordering;
420     sub_mul, mul_sub;
421     Sub { sub }
422     SubAssign { sub_assign }
423     SubAssignRound { sub_assign_round }
424     SubFrom { sub_from }
425     SubFromRound { sub_from_round }
426     MulIncomplete;
427     SubMulIncomplete, SubMulFromIncomplete
428 }
429 
430 trait PrimOps<Long>: AsLong {
add<O: OptFloat>(rop: &mut Float, op1: O, op2: Self, rnd: Round) -> Ordering431     fn add<O: OptFloat>(rop: &mut Float, op1: O, op2: Self, rnd: Round) -> Ordering;
sub<O: OptFloat>(rop: &mut Float, op1: O, op2: Self, rnd: Round) -> Ordering432     fn sub<O: OptFloat>(rop: &mut Float, op1: O, op2: Self, rnd: Round) -> Ordering;
sub_from<O: OptFloat>(rop: &mut Float, op1: Self, op2: O, rnd: Round) -> Ordering433     fn sub_from<O: OptFloat>(rop: &mut Float, op1: Self, op2: O, rnd: Round) -> Ordering;
mul<O: OptFloat>(rop: &mut Float, op1: O, op2: Self, rnd: Round) -> Ordering434     fn mul<O: OptFloat>(rop: &mut Float, op1: O, op2: Self, rnd: Round) -> Ordering;
div<O: OptFloat>(rop: &mut Float, op1: O, op2: Self, rnd: Round) -> Ordering435     fn div<O: OptFloat>(rop: &mut Float, op1: O, op2: Self, rnd: Round) -> Ordering;
div_from<O: OptFloat>(rop: &mut Float, op1: Self, op2: O, rnd: Round) -> Ordering436     fn div_from<O: OptFloat>(rop: &mut Float, op1: Self, op2: O, rnd: Round) -> Ordering;
rem<O: OptFloat>(rop: &mut Float, op1: O, op2: Self, rnd: Round) -> Ordering437     fn rem<O: OptFloat>(rop: &mut Float, op1: O, op2: Self, rnd: Round) -> Ordering;
rem_from<O: OptFloat>(rop: &mut Float, op1: Self, op2: O, rnd: Round) -> Ordering438     fn rem_from<O: OptFloat>(rop: &mut Float, op1: Self, op2: O, rnd: Round) -> Ordering;
pow<O: OptFloat>(rop: &mut Float, op1: O, op2: Self, rnd: Round) -> Ordering439     fn pow<O: OptFloat>(rop: &mut Float, op1: O, op2: Self, rnd: Round) -> Ordering;
pow_from<O: OptFloat>(rop: &mut Float, op1: Self, op2: O, rnd: Round) -> Ordering440     fn pow_from<O: OptFloat>(rop: &mut Float, op1: Self, op2: O, rnd: Round) -> Ordering;
441 }
442 
443 trait AsLong: Copy {
444     type Long;
445 }
446 
447 macro_rules! as_long {
448     ($Long:ty: $($Prim:ty)*) => { $(
449         impl AsLong for $Prim {
450             type Long = $Long;
451         }
452     )* }
453 }
454 
455 as_long! { c_long: i8 i16 i32 i64 i128 isize }
456 as_long! { c_ulong: u8 u16 u32 u64 u128 usize }
457 as_long! { f64: f32 f64 }
458 
459 macro_rules! forward {
460     (fn $fn:ident() -> $deleg_long:path, $deleg:path) => {
461         #[inline]
462         fn $fn<O: OptFloat>(rop: &mut Float, op1: O, op2: Self, rnd: Round) -> Ordering {
463             if let Some(op2) = op2.checked_as() {
464                 $deleg_long(rop, op1, op2, rnd)
465             } else {
466                 let small: SmallFloat = op2.into();
467                 $deleg(rop, op1, &*small, rnd)
468             }
469         }
470     };
471     (fn $fn:ident() -> $deleg:path) => {
472         #[inline]
473         fn $fn<O: OptFloat>(rop: &mut Float, op1: O, op2: Self, rnd: Round) -> Ordering {
474             let small: SmallFloat = op2.into();
475             $deleg(rop, op1, &*small, rnd)
476         }
477     };
478 }
479 macro_rules! reverse {
480     (fn $fn:ident() -> $deleg_long:path, $deleg:path) => {
481         #[inline]
482         fn $fn<O: OptFloat>(rop: &mut Float, op1: Self, op2: O, rnd: Round) -> Ordering {
483             if let Some(op1) = op1.checked_as() {
484                 $deleg_long(rop, op1, op2, rnd)
485             } else {
486                 let small: SmallFloat = op1.into();
487                 $deleg(rop, &*small, op2, rnd)
488             }
489         }
490     };
491     (fn $fn:ident() -> $deleg:path) => {
492         #[inline]
493         fn $fn<O: OptFloat>(rop: &mut Float, op1: Self, op2: O, rnd: Round) -> Ordering {
494             let small: SmallFloat = op1.into();
495             $deleg(rop, &*small, op2, rnd)
496         }
497     };
498 }
499 
500 impl<T> PrimOps<c_long> for T
501 where
502     T: AsLong<Long = c_long> + CheckedCast<c_long> + Into<SmallFloat>,
503 {
504     forward! { fn add() -> xmpfr::add_si, xmpfr::add }
505     forward! { fn sub() -> xmpfr::sub_si, xmpfr::sub }
506     reverse! { fn sub_from() -> xmpfr::si_sub, xmpfr::sub }
507     forward! { fn mul() -> xmpfr::mul_si, xmpfr::mul }
508     forward! { fn div() -> xmpfr::div_si, xmpfr::div }
509     reverse! { fn div_from() -> xmpfr::si_div, xmpfr::div }
510     forward! { fn rem() -> xmpfr::fmod }
511     reverse! { fn rem_from() -> xmpfr::fmod }
512     forward! { fn pow() -> xmpfr::pow_si, xmpfr::pow }
513     reverse! { fn pow_from() -> xmpfr::pow }
514 }
515 
516 impl<T> PrimOps<c_ulong> for T
517 where
518     T: AsLong<Long = c_ulong> + CheckedCast<c_ulong> + Into<SmallFloat>,
519 {
520     forward! { fn add() -> xmpfr::add_ui, xmpfr::add }
521     forward! { fn sub() -> xmpfr::sub_ui, xmpfr::sub }
522     reverse! { fn sub_from() -> xmpfr::ui_sub, xmpfr::sub }
523     forward! { fn mul() -> xmpfr::mul_ui, xmpfr::mul }
524     forward! { fn div() -> xmpfr::div_ui, xmpfr::div }
525     reverse! { fn div_from() -> xmpfr::ui_div, xmpfr::div }
526     forward! { fn rem() -> xmpfr::fmod }
527     reverse! { fn rem_from() -> xmpfr::fmod }
528     forward! { fn pow() -> xmpfr::pow_ui, xmpfr::pow }
529     reverse! { fn pow_from() -> xmpfr::ui_pow, xmpfr::pow }
530 }
531 
532 impl<T> PrimOps<f64> for T
533 where
534     T: AsLong<Long = f64> + CheckedCast<f64> + Into<SmallFloat>,
535 {
536     forward! { fn add() -> xmpfr::add_d, xmpfr::add }
537     forward! { fn sub() -> xmpfr::sub_d, xmpfr::sub }
538     reverse! { fn sub_from() -> xmpfr::d_sub, xmpfr::sub }
539     forward! { fn mul() -> xmpfr::mul_d, xmpfr::mul }
540     forward! { fn div() -> xmpfr::div_d, xmpfr::div }
541     reverse! { fn div_from() -> xmpfr::d_div, xmpfr::div }
542     forward! { fn rem() -> xmpfr::fmod }
543     reverse! { fn rem_from() -> xmpfr::fmod }
544     forward! { fn pow() -> xmpfr::pow }
545     reverse! { fn pow_from() -> xmpfr::pow }
546 }
547 
548 impl<'a> Add for MulIncomplete<'a> {
549     type Output = MulAddMulIncomplete<'a>;
550     #[inline]
add(self, rhs: MulIncomplete<'a>) -> MulAddMulIncomplete<'_>551     fn add(self, rhs: MulIncomplete<'a>) -> MulAddMulIncomplete<'_> {
552         MulAddMulIncomplete { lhs: self, rhs }
553     }
554 }
555 
556 #[derive(Debug)]
557 pub struct MulAddMulIncomplete<'a> {
558     lhs: MulIncomplete<'a>,
559     rhs: MulIncomplete<'a>,
560 }
561 
562 impl AssignRound<MulAddMulIncomplete<'_>> for Float {
563     type Round = Round;
564     type Ordering = Ordering;
565     #[inline]
assign_round(&mut self, src: MulAddMulIncomplete<'_>, round: Round) -> Ordering566     fn assign_round(&mut self, src: MulAddMulIncomplete<'_>, round: Round) -> Ordering {
567         xmpfr::fmma(
568             self,
569             src.lhs.lhs,
570             src.lhs.rhs,
571             src.rhs.lhs,
572             src.rhs.rhs,
573             round,
574         )
575     }
576 }
577 
578 impl<'a> Sub for MulIncomplete<'a> {
579     type Output = MulSubMulIncomplete<'a>;
580     #[inline]
sub(self, rhs: MulIncomplete<'a>) -> MulSubMulIncomplete<'_>581     fn sub(self, rhs: MulIncomplete<'a>) -> MulSubMulIncomplete<'_> {
582         MulSubMulIncomplete { lhs: self, rhs }
583     }
584 }
585 
586 #[derive(Debug)]
587 pub struct MulSubMulIncomplete<'a> {
588     lhs: MulIncomplete<'a>,
589     rhs: MulIncomplete<'a>,
590 }
591 
592 impl AssignRound<MulSubMulIncomplete<'_>> for Float {
593     type Round = Round;
594     type Ordering = Ordering;
595     #[inline]
assign_round(&mut self, src: MulSubMulIncomplete<'_>, round: Round) -> Ordering596     fn assign_round(&mut self, src: MulSubMulIncomplete<'_>, round: Round) -> Ordering {
597         xmpfr::fmms(
598             self,
599             src.lhs.lhs,
600             src.lhs.rhs,
601             src.rhs.lhs,
602             src.rhs.rhs,
603             round,
604         )
605     }
606 }
607 
608 #[inline]
add_mul<O: OptFloat>(rop: &mut Float, add: O, mul: MulIncomplete<'_>, rnd: Round) -> Ordering609 fn add_mul<O: OptFloat>(rop: &mut Float, add: O, mul: MulIncomplete<'_>, rnd: Round) -> Ordering {
610     xmpfr::fma(rop, mul.lhs, mul.rhs, add, rnd)
611 }
612 
613 #[inline]
sub_mul<O: OptFloat>(rop: &mut Float, add: O, mul: MulIncomplete<'_>, rnd: Round) -> Ordering614 fn sub_mul<O: OptFloat>(rop: &mut Float, add: O, mul: MulIncomplete<'_>, rnd: Round) -> Ordering {
615     xmpfr::submul(rop, add, mul.lhs, mul.rhs, rnd)
616 }
617 
618 #[inline]
mul_sub<O: OptFloat>(rop: &mut Float, mul: MulIncomplete<'_>, sub: O, rnd: Round) -> Ordering619 fn mul_sub<O: OptFloat>(rop: &mut Float, mul: MulIncomplete<'_>, sub: O, rnd: Round) -> Ordering {
620     xmpfr::fms(rop, mul.lhs, mul.rhs, sub, rnd)
621 }
622 
623 #[cfg(test)]
624 #[allow(clippy::cognitive_complexity)]
625 pub(crate) mod tests {
626     #[cfg(feature = "rational")]
627     use crate::Rational;
628     use crate::{
629         float::{self, FreeCache, Special},
630         ops::Pow,
631         Float,
632     };
633     #[cfg(feature = "integer")]
634     use {crate::Integer, core::str::FromStr};
635 
same(a: Float, b: Float) -> bool636     pub fn same(a: Float, b: Float) -> bool {
637         if a.is_nan() && b.is_nan() {
638             return true;
639         }
640         if a == b {
641             return true;
642         }
643         if a.prec() == b.prec() {
644             return false;
645         }
646         a == Float::with_val(a.prec(), b)
647     }
648 
649     macro_rules! test_ref_op {
650         ($first:expr, $second:expr) => {
651             assert_eq!(
652                 Float::with_val(53, $first),
653                 $second,
654                 "({}) != ({})",
655                 stringify!($first),
656                 stringify!($second)
657             );
658         };
659     }
660 
661     #[test]
check_ref_op()662     fn check_ref_op() {
663         let lhs = &Float::with_val(53, 12.25);
664         let rhs = &Float::with_val(53, -1.375);
665         let pu = 30_u32;
666         let pi = -15_i32;
667         let ps = 31.625_f32;
668         let pd = -1.5_f64;
669         test_ref_op!(-lhs, -lhs.clone());
670         test_ref_op!(lhs + rhs, lhs.clone() + rhs);
671         test_ref_op!(lhs - rhs, lhs.clone() - rhs);
672         test_ref_op!(lhs * rhs, lhs.clone() * rhs);
673         test_ref_op!(lhs / rhs, lhs.clone() / rhs);
674         test_ref_op!(lhs % rhs, lhs.clone() % rhs);
675         test_ref_op!(lhs.pow(rhs), lhs.clone().pow(rhs));
676 
677         test_ref_op!(lhs + pu, lhs.clone() + pu);
678         test_ref_op!(lhs - pu, lhs.clone() - pu);
679         test_ref_op!(lhs * pu, lhs.clone() * pu);
680         test_ref_op!(lhs / pu, lhs.clone() / pu);
681         test_ref_op!(lhs % pu, lhs.clone() % pu);
682         test_ref_op!(lhs << pu, lhs.clone() << pu);
683         test_ref_op!(lhs >> pu, lhs.clone() >> pu);
684         test_ref_op!(lhs.pow(pu), lhs.clone().pow(pu));
685 
686         test_ref_op!(pu + lhs, pu + lhs.clone());
687         test_ref_op!(pu - lhs, pu - lhs.clone());
688         test_ref_op!(pu * lhs, pu * lhs.clone());
689         test_ref_op!(pu / lhs, pu / lhs.clone());
690         test_ref_op!(pu % lhs, pu % lhs.clone());
691         test_ref_op!(Pow::pow(pu, lhs), Pow::pow(pu, lhs.clone()));
692 
693         test_ref_op!(lhs + pi, lhs.clone() + pi);
694         test_ref_op!(lhs - pi, lhs.clone() - pi);
695         test_ref_op!(lhs * pi, lhs.clone() * pi);
696         test_ref_op!(lhs / pi, lhs.clone() / pi);
697         test_ref_op!(lhs % pi, lhs.clone() % pi);
698         test_ref_op!(lhs << pi, lhs.clone() << pi);
699         test_ref_op!(lhs >> pi, lhs.clone() >> pi);
700         test_ref_op!(lhs.pow(pi), lhs.clone().pow(pi));
701 
702         test_ref_op!(pi + lhs, pi + lhs.clone());
703         test_ref_op!(pi - lhs, pi - lhs.clone());
704         test_ref_op!(pi * lhs, pi * lhs.clone());
705         test_ref_op!(pi / lhs, pi / lhs.clone());
706         test_ref_op!(pi % lhs, pi % lhs.clone());
707 
708         test_ref_op!(lhs + ps, lhs.clone() + ps);
709         test_ref_op!(lhs - ps, lhs.clone() - ps);
710         test_ref_op!(lhs * ps, lhs.clone() * ps);
711         test_ref_op!(lhs / ps, lhs.clone() / ps);
712         test_ref_op!(lhs % ps, lhs.clone() % ps);
713 
714         test_ref_op!(ps + lhs, ps + lhs.clone());
715         test_ref_op!(ps - lhs, ps - lhs.clone());
716         test_ref_op!(ps * lhs, ps * lhs.clone());
717         test_ref_op!(ps / lhs, ps / lhs.clone());
718         test_ref_op!(ps % lhs, ps % lhs.clone());
719 
720         test_ref_op!(lhs + pd, lhs.clone() + pd);
721         test_ref_op!(lhs - pd, lhs.clone() - pd);
722         test_ref_op!(lhs * pd, lhs.clone() * pd);
723         test_ref_op!(lhs / pd, lhs.clone() / pd);
724         test_ref_op!(lhs % pd, lhs.clone() % pd);
725 
726         test_ref_op!(pd + lhs, pd + lhs.clone());
727         test_ref_op!(pd - lhs, pd - lhs.clone());
728         test_ref_op!(pd * lhs, pd * lhs.clone());
729         test_ref_op!(pd / lhs, pd / lhs.clone());
730         test_ref_op!(pd % lhs, pd % lhs.clone());
731 
732         float::free_cache(FreeCache::All);
733     }
734 
735     macro_rules! check_others {
736         (&$list:expr, $against:expr) => {
737             for op in &$list {
738                 let fop = Float::with_val(150, op);
739                 for b in &$against {
740                     assert!(same(b.clone() + op, b.clone() + &fop));
741                     assert!(same(b.clone() - op, b.clone() - &fop));
742                     assert!(same(b.clone() * op, b.clone() * &fop));
743                     assert!(same(b.clone() / op, b.clone() / &fop));
744                     assert!(same(op + b.clone(), fop.clone() + b));
745                     assert!(same(op - b.clone(), fop.clone() - b));
746                     assert!(same(op * b.clone(), fop.clone() * b));
747                     assert!(same(op / b.clone(), fop.clone() / b));
748                 }
749             }
750         };
751         ($list:expr, $against:expr) => {
752             for op in $list {
753                 let fop = Float::with_val(150, *op);
754                 for b in &$against {
755                     assert!(same(b.clone() + *op, b.clone() + &fop));
756                     assert!(same(b.clone() - *op, b.clone() - &fop));
757                     assert!(same(b.clone() * *op, b.clone() * &fop));
758                     assert!(same(b.clone() / *op, b.clone() / &fop));
759                     assert!(same(b.clone() % *op, b.clone() % &fop));
760                     assert!(same(*op + b.clone(), fop.clone() + b));
761                     assert!(same(*op - b.clone(), fop.clone() - b));
762                     assert!(same(*op * b.clone(), fop.clone() * b));
763                     assert!(same(*op / b.clone(), fop.clone() / b));
764                     assert!(same(*op % b.clone(), fop.clone() % b));
765                     assert!(same(b.clone().pow(*op), b.clone().pow(&fop)));
766                     assert!(same(op.pow(b.clone()), fop.clone().pow(b)));
767                 }
768             }
769         };
770     }
771 
772     #[test]
check_arith_others()773     fn check_arith_others() {
774         use crate::tests::{F32, F64, I128, I16, I32, I64, I8, U128, U16, U32, U64, U8};
775         let large = [
776             Float::with_val(20, Special::Zero),
777             Float::with_val(20, Special::NegZero),
778             Float::with_val(20, Special::Infinity),
779             Float::with_val(20, Special::NegInfinity),
780             Float::with_val(20, Special::Nan),
781             Float::with_val(20, 1),
782             Float::with_val(20, -1),
783             Float::with_val(20, 999_999e100),
784             Float::with_val(20, 999_999e-100),
785             Float::with_val(20, -999_999e100),
786             Float::with_val(20, -999_999e-100),
787         ];
788         #[cfg(feature = "integer")]
789         let z = [
790             Integer::from(0),
791             Integer::from(1),
792             Integer::from(-1),
793             Integer::from_str("-1000000000000").unwrap(),
794             Integer::from_str("1000000000000").unwrap(),
795         ];
796         #[cfg(feature = "rational")]
797         let q = [
798             Rational::from(0),
799             Rational::from(1),
800             Rational::from(-1),
801             Rational::from_str("-1000000000000/33333333333").unwrap(),
802             Rational::from_str("1000000000000/33333333333").unwrap(),
803         ];
804 
805         let against = large
806             .iter()
807             .cloned()
808             .chain(U32.iter().map(|&x| Float::with_val(20, x)))
809             .chain(I32.iter().map(|&x| Float::with_val(20, x)))
810             .chain(U64.iter().map(|&x| Float::with_val(20, x)))
811             .chain(I64.iter().map(|&x| Float::with_val(20, x)))
812             .chain(U128.iter().map(|&x| Float::with_val(20, x)))
813             .chain(I128.iter().map(|&x| Float::with_val(20, x)))
814             .chain(F32.iter().map(|&x| Float::with_val(20, x)))
815             .chain(F64.iter().map(|&x| Float::with_val(20, x)))
816             .collect::<Vec<Float>>();
817         #[cfg(feature = "integer")]
818         let mut against = against;
819         #[cfg(feature = "integer")]
820         against.extend(z.iter().map(|x| Float::with_val(20, x)));
821         #[cfg(feature = "rational")]
822         against.extend(q.iter().map(|x| Float::with_val(20, x)));
823 
824         check_others!(I8, against);
825         check_others!(I16, against);
826         check_others!(I32, against);
827         check_others!(I64, against);
828         check_others!(I128, against);
829         check_others!(U8, against);
830         check_others!(U16, against);
831         check_others!(U32, against);
832         check_others!(U64, against);
833         check_others!(U128, against);
834         check_others!(F32, against);
835         check_others!(F64, against);
836         #[cfg(feature = "integer")]
837         check_others!(&z, against);
838         #[cfg(feature = "rational")]
839         check_others!(&q, against);
840 
841         float::free_cache(FreeCache::All);
842     }
843 }
844