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