1#[cfg(feature = "integer")]
18use crate::Integer;
19#[cfg(feature = "rational")]
20use crate::Rational;
21use crate::complex::MiniComplex;
22use crate::ext::xmpc;
23use crate::ext::xmpc::{NEAREST2, OptComplex, Ordering2, Round2};
24use crate::float::MiniFloat;
25use crate::ops::{
26 AddAssignRound, AddFrom, AddFromRound, AssignRound, CompleteRound, DivAssignRound, DivFrom,
27 DivFromRound, MulAssignRound, MulFrom, MulFromRound, NegAssign, Pow, PowAssign, PowAssignRound,
28 PowFrom, PowFromRound, SubAssignRound, SubFrom, SubFromRound,
29};
30use crate::{Complex, Float};
31use az::{CheckedAs, CheckedCast};
32use core::ffi::{c_long, c_ulong};
33use core::ops::{
34 Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Shl, ShlAssign, Shr, ShrAssign, Sub,
35 SubAssign,
36};
37
38impl Neg for Complex {
39 type Output = Complex;
40 #[inline]
41 fn neg(mut self) -> Complex {
42 self.neg_assign();
43 self
44 }
45}
46
47impl NegAssign for Complex {
48 #[inline]
49 fn neg_assign(&mut self) {
50 xmpc::neg(self, (), NEAREST2);
51 }
52}
53
54impl<'a> Neg for &'a Complex {
55 type Output = NegIncomplete<'a>;
56 #[inline]
57 fn neg(self) -> NegIncomplete<'a> {
58 NegIncomplete { val: self }
59 }
60}
61
62#[derive(Debug)]
63pub struct NegIncomplete<'a> {
64 val: &'a Complex,
65}
66
67impl AssignRound<NegIncomplete<'_>> for Complex {
68 type Round = Round2;
69 type Ordering = Ordering2;
70 #[inline]
71 fn assign_round(&mut self, src: NegIncomplete<'_>, round: Round2) -> Ordering2 {
72 xmpc::neg(self, src.val, round)
73 }
74}
75
76impl CompleteRound for NegIncomplete<'_> {
77 type Completed = Complex;
78 type Prec = (u32, u32);
79 type Round = Round2;
80 type Ordering = Ordering2;
81 #[inline]
82 fn complete_round(self, prec: (u32, u32), round: Round2) -> (Complex, Ordering2) {
83 Complex::with_val_round(prec, self, round)
84 }
85}
86
87arith_binary_self_round! {
88 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
89 xmpc::add;
90 Add { add }
91 AddAssign { add_assign }
92 AddAssignRound { add_assign_round }
93 AddFrom { add_from }
94 AddFromRound { add_from_round }
95 AddIncomplete
96}
97arith_binary_self_round! {
98 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
99 xmpc::sub;
100 Sub { sub }
101 SubAssign { sub_assign }
102 SubAssignRound { sub_assign_round }
103 SubFrom { sub_from }
104 SubFromRound { sub_from_round }
105 SubIncomplete
106}
107arith_binary_self_round! {
108 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
109 xmpc::mul;
110 Mul { mul }
111 MulAssign { mul_assign }
112 MulAssignRound { mul_assign_round }
113 MulFrom { mul_from }
114 MulFromRound { mul_from_round }
115 MulIncomplete
116}
117arith_binary_self_round! {
118 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
119 xmpc::div;
120 Div { div }
121 DivAssign { div_assign }
122 DivAssignRound { div_assign_round }
123 DivFrom { div_from }
124 DivFromRound { div_from_round }
125 DivIncomplete
126}
127arith_binary_self_round! {
128 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
129 xmpc::pow;
130 Pow { pow }
131 PowAssign { pow_assign }
132 PowAssignRound { pow_assign_round }
133 PowFrom { pow_from }
134 PowFromRound { pow_from_round }
135 PowIncomplete
136}
137
138arith_commut_round! {
139 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
140 xmpc::add_fr;
141 Add { add }
142 AddAssign { add_assign }
143 AddAssignRound { add_assign_round }
144 AddFrom { add_from }
145 AddFromRound { add_from_round }
146 Float;
147 AddFloatIncomplete, AddOwnedFloatIncomplete
148}
149arith_noncommut_round! {
150 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
151 xmpc::sub_fr, xmpc::fr_sub;
152 Sub { sub }
153 SubAssign { sub_assign }
154 SubAssignRound { sub_assign_round }
155 SubFrom { sub_from }
156 SubFromRound { sub_from_round }
157 Float;
158 SubFloatIncomplete, SubOwnedFloatIncomplete;
159 SubFromFloatIncomplete, SubFromOwnedFloatIncomplete
160}
161arith_commut_round! {
162 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
163 xmpc::mul_fr;
164 Mul { mul }
165 MulAssign { mul_assign }
166 MulAssignRound { mul_assign_round }
167 MulFrom { mul_from }
168 MulFromRound { mul_from_round }
169 Float;
170 MulFloatIncomplete, MulOwnedFloatIncomplete
171}
172arith_noncommut_round! {
173 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
174 xmpc::div_fr, xmpc::fr_div;
175 Div { div }
176 DivAssign { div_assign }
177 DivAssignRound { div_assign_round }
178 DivFrom { div_from }
179 DivFromRound { div_from_round }
180 Float;
181 DivFloatIncomplete, DivOwnedFloatIncomplete;
182 DivFromFloatIncomplete, DivFromOwnedFloatIncomplete
183}
184arith_forward_round! {
185 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
186 xmpc::pow_fr;
187 Pow { pow }
188 PowAssign { pow_assign }
189 PowAssignRound { pow_assign_round }
190 Float;
191 PowFloatIncomplete, PowOwnedFloatIncomplete
192}
193#[cfg(feature = "integer")]
194arith_forward_round! {
195 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
196 xmpc::pow_z;
197 Pow { pow }
198 PowAssign { pow_assign }
199 PowAssignRound { pow_assign_round }
200 Integer;
201 PowIntegerIncomplete, PowOwnedIntegerIncomplete
202}
203
204arith_prim_commut_round! {
205 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
206 PrimOps::add;
207 Add { add }
208 AddAssign { add_assign }
209 AddAssignRound { add_assign_round }
210 AddFrom { add_from }
211 AddFromRound { add_from_round }
212 i8, AddI8Incomplete;
213 i16, AddI16Incomplete;
214 i32, AddI32Incomplete;
215 i64, AddI64Incomplete;
216 i128, AddI128Incomplete;
217 isize, AddIsizeIncomplete;
218 u8, AddU8Incomplete;
219 u16, AddU16Incomplete;
220 u32, AddU32Incomplete;
221 u64, AddU64Incomplete;
222 u128, AddU128Incomplete;
223 usize, AddUsizeIncomplete;
224 f32, AddF32Incomplete;
225 f64, AddF64Incomplete;
226}
227#[cfg(feature = "nightly-float")]
228arith_prim_commut_round! {
229 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
230 PrimOps::add;
231 Add { add }
232 AddAssign { add_assign }
233 AddAssignRound { add_assign_round }
234 AddFrom { add_from }
235 AddFromRound { add_from_round }
236 f16, AddF16Incomplete;
237 f128, AddF128Incomplete;
238}
239arith_prim_noncommut_round! {
240 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
241 PrimOps::sub, PrimOps::sub_from;
242 Sub { sub }
243 SubAssign { sub_assign }
244 SubAssignRound { sub_assign_round }
245 SubFrom { sub_from }
246 SubFromRound { sub_from_round }
247 i8, SubI8Incomplete, SubFromI8Incomplete;
248 i16, SubI16Incomplete, SubFromI16Incomplete;
249 i32, SubI32Incomplete, SubFromI32Incomplete;
250 i64, SubI64Incomplete, SubFromI64Incomplete;
251 i128, SubI128Incomplete, SubFromI128Incomplete;
252 isize, SubIsizeIncomplete, SubFromIsizeIncomplete;
253 u8, SubU8Incomplete, SubFromU8Incomplete;
254 u16, SubU16Incomplete, SubFromU16Incomplete;
255 u32, SubU32Incomplete, SubFromU32Incomplete;
256 u64, SubU64Incomplete, SubFromU64Incomplete;
257 u128, SubU128Incomplete, SubFromU128Incomplete;
258 usize, SubUsizeIncomplete, SubFromUsizeIncomplete;
259 f32, SubF32Incomplete, SubFromF32Incomplete;
260 f64, SubF64Incomplete, SubFromF64Incomplete;
261}
262#[cfg(feature = "nightly-float")]
263arith_prim_noncommut_round! {
264 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
265 PrimOps::sub, PrimOps::sub_from;
266 Sub { sub }
267 SubAssign { sub_assign }
268 SubAssignRound { sub_assign_round }
269 SubFrom { sub_from }
270 SubFromRound { sub_from_round }
271 f16, SubF16Incomplete, SubFromF16Incomplete;
272 f128, SubF128Incomplete, SubFromF128Incomplete;
273}
274arith_prim_commut_round! {
275 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
276 PrimOps::mul;
277 Mul { mul }
278 MulAssign { mul_assign }
279 MulAssignRound { mul_assign_round }
280 MulFrom { mul_from }
281 MulFromRound { mul_from_round }
282 i8, MulI8Incomplete;
283 i16, MulI16Incomplete;
284 i32, MulI32Incomplete;
285 i64, MulI64Incomplete;
286 i128, MulI128Incomplete;
287 isize, MulIsizeIncomplete;
288 u8, MulU8Incomplete;
289 u16, MulU16Incomplete;
290 u32, MulU32Incomplete;
291 u64, MulU64Incomplete;
292 u128, MulU128Incomplete;
293 usize, MulUsizeIncomplete;
294 f32, MulF32Incomplete;
295 f64, MulF64Incomplete;
296}
297#[cfg(feature = "nightly-float")]
298arith_prim_commut_round! {
299 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
300 PrimOps::mul;
301 Mul { mul }
302 MulAssign { mul_assign }
303 MulAssignRound { mul_assign_round }
304 MulFrom { mul_from }
305 MulFromRound { mul_from_round }
306 f16, MulF16Incomplete;
307 f128, MulF128Incomplete;
308}
309arith_prim_noncommut_round! {
310 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
311 PrimOps::div, PrimOps::div_from;
312 Div { div }
313 DivAssign { div_assign }
314 DivAssignRound { div_assign_round }
315 DivFrom { div_from }
316 DivFromRound { div_from_round }
317 i8, DivI8Incomplete, DivFromI8Incomplete;
318 i16, DivI16Incomplete, DivFromI16Incomplete;
319 i32, DivI32Incomplete, DivFromI32Incomplete;
320 i64, DivI64Incomplete, DivFromI64Incomplete;
321 i128, DivI128Incomplete, DivFromI128Incomplete;
322 isize, DivIsizeIncomplete, DivFromIsizeIncomplete;
323 u8, DivU8Incomplete, DivFromU8Incomplete;
324 u16, DivU16Incomplete, DivFromU16Incomplete;
325 u32, DivU32Incomplete, DivFromU32Incomplete;
326 u64, DivU64Incomplete, DivFromU64Incomplete;
327 u128, DivU128Incomplete, DivFromU128Incomplete;
328 usize, DivUsizeIncomplete, DivFromUsizeIncomplete;
329 f32, DivF32Incomplete, DivFromF32Incomplete;
330 f64, DivF64Incomplete, DivFromF64Incomplete;
331}
332#[cfg(feature = "nightly-float")]
333arith_prim_noncommut_round! {
334 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
335 PrimOps::div, PrimOps::div_from;
336 Div { div }
337 DivAssign { div_assign }
338 DivAssignRound { div_assign_round }
339 DivFrom { div_from }
340 DivFromRound { div_from_round }
341 f16, DivF16Incomplete, DivFromF16Incomplete;
342 f128, DivF128Incomplete, DivFromF128Incomplete;
343}
344arith_prim_noncommut_round! {
345 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
346 PrimOps::pow, PrimOps::pow_from;
347 Pow { pow }
348 PowAssign { pow_assign }
349 PowAssignRound { pow_assign_round }
350 PowFrom { pow_from }
351 PowFromRound { pow_from_round }
352 i8, PowI8Incomplete, PowFromI8Incomplete;
353 i16, PowI16Incomplete, PowFromI16Incomplete;
354 i32, PowI32Incomplete, PowFromI32Incomplete;
355 i64, PowI64Incomplete, PowFromI64Incomplete;
356 i128, PowI128Incomplete, PowFromI128Incomplete;
357 isize, PowIsizeIncomplete, PowFromIsizeIncomplete;
358 u8, PowU8Incomplete, PowFromU8Incomplete;
359 u16, PowU16Incomplete, PowFromU16Incomplete;
360 u32, PowU32Incomplete, PowFromU32Incomplete;
361 u64, PowU64Incomplete, PowFromU64Incomplete;
362 u128, PowU128Incomplete, PowFromU128Incomplete;
363 usize, PowUsizeIncomplete, PowFromUsizeIncomplete;
364 f32, PowF32Incomplete, PowFromF32Incomplete;
365 f64, PowF64Incomplete, PowFromF64Incomplete;
366}
367#[cfg(feature = "nightly-float")]
368arith_prim_noncommut_round! {
369 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
370 PrimOps::pow, PrimOps::pow_from;
371 Pow { pow }
372 PowAssign { pow_assign }
373 PowAssignRound { pow_assign_round }
374 PowFrom { pow_from }
375 PowFromRound { pow_from_round }
376 f16, PowF16Incomplete, PowFromF16Incomplete;
377 f128, PowF128Incomplete, PowFromF128Incomplete;
378}
379
380#[cfg(feature = "integer")]
381arith_commut_round! {
382 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
383 xmpc::add_z;
384 Add { add }
385 AddAssign { add_assign }
386 AddAssignRound { add_assign_round }
387 AddFrom { add_from }
388 AddFromRound { add_from_round }
389 Integer;
390 AddIntegerIncomplete, AddOwnedIntegerIncomplete
391}
392#[cfg(feature = "integer")]
393arith_noncommut_round! {
394 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
395 xmpc::sub_z, xmpc::z_sub;
396 Sub { sub }
397 SubAssign { sub_assign }
398 SubAssignRound { sub_assign_round }
399 SubFrom { sub_from }
400 SubFromRound { sub_from_round }
401 Integer;
402 SubIntegerIncomplete, SubOwnedIntegerIncomplete;
403 SubFromIntegerIncomplete, SubFromOwnedIntegerIncomplete
404}
405#[cfg(feature = "integer")]
406arith_commut_round! {
407 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
408 xmpc::mul_z;
409 Mul { mul }
410 MulAssign { mul_assign }
411 MulAssignRound { mul_assign_round }
412 MulFrom { mul_from }
413 MulFromRound { mul_from_round }
414 Integer;
415 MulIntegerIncomplete, MulOwnedIntegerIncomplete
416}
417#[cfg(feature = "integer")]
418arith_forward_round! {
419 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
420 xmpc::div_z;
421 Div { div }
422 DivAssign { div_assign }
423 DivAssignRound { div_assign_round }
424 Integer;
425 DivIntegerIncomplete, DivOwnedIntegerIncomplete
426}
427#[cfg(feature = "rational")]
428arith_commut_round! {
429 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
430 xmpc::add_q;
431 Add { add }
432 AddAssign { add_assign }
433 AddAssignRound { add_assign_round }
434 AddFrom { add_from }
435 AddFromRound { add_from_round }
436 Rational;
437 AddRationalIncomplete, AddOwnedRationalIncomplete
438}
439#[cfg(feature = "rational")]
440arith_noncommut_round! {
441 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
442 xmpc::sub_q, xmpc::q_sub;
443 Sub { sub }
444 SubAssign { sub_assign }
445 SubAssignRound { sub_assign_round }
446 SubFrom { sub_from }
447 SubFromRound { sub_from_round }
448 Rational;
449 SubRationalIncomplete, SubOwnedRationalIncomplete;
450 SubFromRationalIncomplete, SubFromOwnedRationalIncomplete
451}
452#[cfg(feature = "rational")]
453arith_commut_round! {
454 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
455 xmpc::mul_q;
456 Mul { mul }
457 MulAssign { mul_assign }
458 MulAssignRound { mul_assign_round }
459 MulFrom { mul_from }
460 MulFromRound { mul_from_round }
461 Rational;
462 MulRationalIncomplete, MulOwnedRationalIncomplete
463}
464#[cfg(feature = "rational")]
465arith_forward_round! {
466 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
467 xmpc::div_q;
468 Div { div }
469 DivAssign { div_assign }
470 DivAssignRound { div_assign_round }
471 Rational;
472 DivRationalIncomplete, DivOwnedRationalIncomplete
473}
474
475arith_prim_exact_round! {
476 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
477 xmpc::shl_u32;
478 Shl { shl }
479 ShlAssign { shl_assign }
480 u32, ShlU32Incomplete;
481}
482arith_prim_exact_round! {
483 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
484 xmpc::shr_u32;
485 Shr { shr }
486 ShrAssign { shr_assign }
487 u32, ShrU32Incomplete;
488}
489arith_prim_exact_round! {
490 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
491 xmpc::shl_i32;
492 Shl { shl }
493 ShlAssign { shl_assign }
494 i32, ShlI32Incomplete;
495}
496arith_prim_exact_round! {
497 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
498 xmpc::shr_i32;
499 Shr { shr }
500 ShrAssign { shr_assign }
501 i32, ShrI32Incomplete;
502}
503arith_prim_exact_round! {
504 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
505 xmpc::shl_usize;
506 Shl { shl }
507 ShlAssign { shl_assign }
508 usize, ShlUsizeIncomplete;
509}
510arith_prim_exact_round! {
511 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
512 xmpc::shr_usize;
513 Shr { shr }
514 ShrAssign { shr_assign }
515 usize, ShrUsizeIncomplete;
516}
517arith_prim_exact_round! {
518 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
519 xmpc::shl_isize;
520 Shl { shl }
521 ShlAssign { shl_assign }
522 isize, ShlIsizeIncomplete;
523}
524arith_prim_exact_round! {
525 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
526 xmpc::shr_isize;
527 Shr { shr }
528 ShrAssign { shr_assign }
529 isize, ShrIsizeIncomplete;
530}
531
532mul_op_commut_round! {
533 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
534 add_mul;
535 Add { add }
536 AddAssign { add_assign }
537 AddAssignRound { add_assign_round }
538 AddFrom { add_from }
539 AddFromRound { add_from_round }
540 MulIncomplete;
541 AddMulIncomplete
542}
543mul_op_noncommut_round! {
544 Complex, (u32, u32), Round2, NEAREST2, Ordering2;
545 sub_mul, mul_sub;
546 Sub { sub }
547 SubAssign { sub_assign }
548 SubAssignRound { sub_assign_round }
549 SubFrom { sub_from }
550 SubFromRound { sub_from_round }
551 MulIncomplete;
552 SubMulIncomplete, SubMulFromIncomplete
553}
554
555trait PrimOps<Long>: AsLong {
556 fn add<O: OptComplex>(rop: &mut Complex, op1: O, op2: Self, rnd: Round2) -> Ordering2;
557 fn sub<O: OptComplex>(rop: &mut Complex, op1: O, op2: Self, rnd: Round2) -> Ordering2;
558 fn sub_from<O: OptComplex>(rop: &mut Complex, op1: Self, op2: O, rnd: Round2) -> Ordering2;
559 fn mul<O: OptComplex>(rop: &mut Complex, op1: O, op2: Self, rnd: Round2) -> Ordering2;
560 fn div<O: OptComplex>(rop: &mut Complex, op1: O, op2: Self, rnd: Round2) -> Ordering2;
561 fn div_from<O: OptComplex>(rop: &mut Complex, op1: Self, op2: O, rnd: Round2) -> Ordering2;
562 fn pow<O: OptComplex>(rop: &mut Complex, op1: O, op2: Self, rnd: Round2) -> Ordering2;
563 fn pow_from<O: OptComplex>(rop: &mut Complex, op1: Self, op2: O, rnd: Round2) -> Ordering2;
564}
565
566trait AsLong: Copy {
567 type Long;
568}
569
570macro_rules! as_long {
571 ($Long:ty: $($Prim:ty)*) => { $(
572 impl AsLong for $Prim {
573 type Long = $Long;
574 }
575 )* }
576}
577
578as_long! { c_long: i8 i16 i32 i64 i128 isize }
579as_long! { c_ulong: u8 u16 u32 u64 u128 usize }
580as_long! { f64: f32 f64 }
581#[cfg(feature = "nightly-float")]
582as_long! { f64: f16 }
583#[cfg(feature = "nightly-float")]
584as_long! { f128: f128 }
585
586macro_rules! forward {
587 (fn $fn:ident() -> $deleg_long:path, $deleg:path) => {
588 #[inline]
589 fn $fn<O: OptComplex>(rop: &mut Complex, op1: O, op2: Self, rnd: Round2) -> Ordering2 {
590 if let Some(op2) = op2.checked_as() {
591 $deleg_long(rop, op1, op2, rnd)
592 } else {
593 let mut small: MiniFloat = op2.into();
594 $deleg(rop, op1, small.borrow_excl(), rnd)
595 }
596 }
597 };
598 (fn $fn:ident() -> $deleg:path) => {
599 #[inline]
600 fn $fn<O: OptComplex>(rop: &mut Complex, op1: O, op2: Self, rnd: Round2) -> Ordering2 {
601 let mut small: MiniFloat = op2.into();
602 $deleg(rop, op1, small.borrow_excl(), rnd)
603 }
604 };
605 (f64: fn $fn:ident() -> $deleg:path) => {
606 #[inline]
607 fn $fn<O: OptComplex>(rop: &mut Complex, op1: O, op2: Self, rnd: Round2) -> Ordering2 {
608 let f = f64::from(op2);
609 $deleg(rop, op1, f, rnd)
610 }
611 };
612}
613macro_rules! reverse {
614 (fn $fn:ident() -> $deleg_long:path, $deleg:path) => {
615 #[inline]
616 fn $fn<O: OptComplex>(rop: &mut Complex, op1: Self, op2: O, rnd: Round2) -> Ordering2 {
617 if let Some(op1) = op1.checked_as() {
618 $deleg_long(rop, op1, op2, rnd)
619 } else {
620 let mut small: MiniFloat = op1.into();
621 $deleg(rop, small.borrow_excl(), op2, rnd)
622 }
623 }
624 };
625 (fn $fn:ident() -> $deleg:path) => {
626 #[inline]
627 fn $fn<O: OptComplex>(rop: &mut Complex, op1: Self, op2: O, rnd: Round2) -> Ordering2 {
628 let mut small: MiniFloat = op1.into();
629 $deleg(rop, small.borrow_excl(), op2, rnd)
630 }
631 };
632 (f64: fn $fn:ident() -> $deleg:path) => {
633 #[inline]
634 fn $fn<O: OptComplex>(rop: &mut Complex, op1: Self, op2: O, rnd: Round2) -> Ordering2 {
635 let f = f64::from(op1);
636 $deleg(rop, f, op2, rnd)
637 }
638 };
639}
640
641impl<T> PrimOps<c_long> for T
642where
643 T: AsLong<Long = c_long> + CheckedCast<c_long> + Into<MiniFloat> + Into<MiniComplex>,
644{
645 forward! { fn add() -> xmpc::add_si, xmpc::add_fr }
646 forward! { fn sub() -> xmpc::sub_si, xmpc::sub_fr }
647 reverse! { fn sub_from() -> xmpc::si_sub, xmpc::fr_sub }
648 forward! { fn mul() -> xmpc::mul_si, xmpc::mul_fr }
649 forward! { fn div() -> xmpc::div_si, xmpc::div_fr }
650 reverse! { fn div_from() -> xmpc::si_div, xmpc::fr_div }
651
652 #[inline]
653 fn pow<O: OptComplex>(rop: &mut Complex, op1: O, op2: Self, rnd: Round2) -> Ordering2 {
654 let mut small: MiniFloat = op2.into();
655 xmpc::pow_fr(rop, op1, small.borrow_excl(), rnd)
656 }
657
658 #[inline]
659 fn pow_from<O: OptComplex>(rop: &mut Complex, op1: Self, op2: O, rnd: Round2) -> Ordering2 {
660 let mut small: MiniComplex = op1.into();
661 xmpc::pow(rop, small.borrow_excl(), op2, rnd)
662 }
663}
664
665impl<T> PrimOps<c_ulong> for T
666where
667 T: AsLong<Long = c_ulong> + CheckedCast<c_ulong> + Into<MiniFloat> + Into<MiniComplex>,
668{
669 forward! { fn add() -> xmpc::add_ui, xmpc::add_fr }
670 forward! { fn sub() -> xmpc::sub_ui, xmpc::sub_fr }
671 reverse! { fn sub_from() -> xmpc::ui_sub, xmpc::fr_sub }
672 forward! { fn mul() -> xmpc::mul_ui, xmpc::mul_fr }
673 forward! { fn div() -> xmpc::div_ui, xmpc::div_fr }
674 reverse! { fn div_from() -> xmpc::ui_div, xmpc::fr_div }
675
676 #[inline]
677 fn pow<O: OptComplex>(rop: &mut Complex, op1: O, op2: Self, rnd: Round2) -> Ordering2 {
678 let mut small: MiniFloat = op2.into();
679 xmpc::pow_fr(rop, op1, small.borrow_excl(), rnd)
680 }
681
682 #[inline]
683 fn pow_from<O: OptComplex>(rop: &mut Complex, op1: Self, op2: O, rnd: Round2) -> Ordering2 {
684 let mut small: MiniComplex = op1.into();
685 xmpc::pow(rop, small.borrow_excl(), op2, rnd)
686 }
687}
688
689impl<T> PrimOps<f64> for T
690where
691 T: AsLong<Long = f64> + Into<MiniFloat> + Into<MiniComplex>,
692 f64: From<T>,
693{
694 forward! { f64: fn add() -> xmpc::add_d }
695 forward! { f64: fn sub() -> xmpc::sub_d }
696 reverse! { f64: fn sub_from() -> xmpc::d_sub }
697 forward! { f64: fn mul() -> xmpc::mul_d }
698 forward! { f64: fn div() -> xmpc::div_d }
699 reverse! { f64: fn div_from() -> xmpc::d_div }
700
701 #[inline]
702 fn pow<O: OptComplex>(rop: &mut Complex, op1: O, op2: Self, rnd: Round2) -> Ordering2 {
703 let mut small: MiniFloat = op2.into();
704 xmpc::pow_fr(rop, op1, small.borrow_excl(), rnd)
705 }
706
707 #[inline]
708 fn pow_from<O: OptComplex>(rop: &mut Complex, op1: Self, op2: O, rnd: Round2) -> Ordering2 {
709 let mut small: MiniComplex = op1.into();
710 xmpc::pow(rop, small.borrow_excl(), op2, rnd)
711 }
712}
713
714#[cfg(feature = "nightly-float")]
715impl<T> PrimOps<f128> for T
716where
717 T: AsLong<Long = f128> + Into<MiniFloat> + Into<MiniComplex>,
718{
719 forward! { fn add() -> xmpc::add_fr }
720 forward! { fn sub() -> xmpc::sub_fr }
721 reverse! { fn sub_from() -> xmpc::fr_sub }
722 forward! { fn mul() -> xmpc::mul_fr }
723 forward! { fn div() -> xmpc::div_fr }
724 reverse! { fn div_from() -> xmpc::fr_div }
725
726 #[inline]
727 fn pow<O: OptComplex>(rop: &mut Complex, op1: O, op2: Self, rnd: Round2) -> Ordering2 {
728 let mut small: MiniFloat = op2.into();
729 xmpc::pow_fr(rop, op1, small.borrow_excl(), rnd)
730 }
731
732 #[inline]
733 fn pow_from<O: OptComplex>(rop: &mut Complex, op1: Self, op2: O, rnd: Round2) -> Ordering2 {
734 let mut small: MiniComplex = op1.into();
735 xmpc::pow(rop, small.borrow_excl(), op2, rnd)
736 }
737}
738
739#[inline]
740fn add_mul<O: OptComplex>(
741 rop: &mut Complex,
742 add: O,
743 mul: MulIncomplete<'_>,
744 rnd: Round2,
745) -> Ordering2 {
746 xmpc::fma(rop, mul.lhs, mul.rhs, add, rnd)
747}
748
749#[inline]
750fn sub_mul<O: OptComplex>(
751 rop: &mut Complex,
752 add: O,
753 mul: MulIncomplete<'_>,
754 rnd: Round2,
755) -> Ordering2 {
756 xmpc::submul(rop, add, mul.lhs, mul.rhs, rnd)
757}
758
759#[inline]
760fn mul_sub<O: OptComplex>(
761 rop: &mut Complex,
762 mul: MulIncomplete<'_>,
763 sub: O,
764 rnd: Round2,
765) -> Ordering2 {
766 xmpc::mulsub(rop, mul.lhs, mul.rhs, sub, rnd)
767}
768
769#[cfg(test)]
770mod tests {
771 #[cfg(feature = "integer")]
772 use crate::Integer;
773 #[cfg(feature = "rational")]
774 use crate::Rational;
775 use crate::float;
776 use crate::float::arith::tests as float_tests;
777 use crate::float::{FreeCache, Special};
778 use crate::ops::{NegAssign, Pow};
779 use crate::{Complex, Float};
780 #[cfg(feature = "integer")]
781 use core::str::FromStr;
782
783 #[test]
784 fn check_neg() {
785 let mut a = Complex::with_val(53, (Special::Zero, Special::NegZero));
786 assert!(a.real().is_sign_positive() && a.imag().is_sign_negative());
787 a.neg_assign();
788 assert!(a.real().is_sign_negative() && a.imag().is_sign_positive());
789 let a = -a;
790 assert!(a.real().is_sign_positive() && a.imag().is_sign_negative());
791 let a = Complex::with_val(53, -&a);
792 assert!(a.real().is_sign_negative() && a.imag().is_sign_positive());
793
794 float::free_cache(FreeCache::All);
795 }
796
797 fn same(a: Complex, b: Complex) -> bool {
798 let (re_a, im_a) = a.into_real_imag();
799 let (re_b, im_b) = b.into_real_imag();
800 float_tests::same(re_a, re_b) && float_tests::same(im_a, im_b)
801 }
802
803 macro_rules! test_ref_op {
804 ($first:expr, $second:expr) => {
805 assert_eq!(
806 Complex::with_val(53, $first),
807 $second,
808 "({}) != ({})",
809 stringify!($first),
810 stringify!($second)
811 );
812 };
813 }
814
815 #[test]
816 fn check_ref_op() {
817 let lhs = Complex::with_val(53, (12.25, -1.375));
818 let rhs = Complex::with_val(53, (-1.375, 13));
819 let pu = 30_u32;
820 let pi = -15_i32;
821 let ps = 31.625_f32;
822 let pd = -1.5_f64;
823 test_ref_op!(-&lhs, -lhs.clone());
824 test_ref_op!(&lhs + &rhs, lhs.clone() + &rhs);
825 test_ref_op!(&lhs - &rhs, lhs.clone() - &rhs);
826 test_ref_op!(&lhs * &rhs, lhs.clone() * &rhs);
827 test_ref_op!(&lhs / &rhs, lhs.clone() / &rhs);
828 test_ref_op!((&lhs).pow(&rhs), lhs.clone().pow(&rhs));
829
830 test_ref_op!(&lhs + pu, lhs.clone() + pu);
831 test_ref_op!(&lhs - pu, lhs.clone() - pu);
832 test_ref_op!(&lhs * pu, lhs.clone() * pu);
833 test_ref_op!(&lhs / pu, lhs.clone() / pu);
834 test_ref_op!(&lhs << pu, lhs.clone() << pu);
835 test_ref_op!(&lhs >> pu, lhs.clone() >> pu);
836 test_ref_op!((&lhs).pow(pu), lhs.clone().pow(pu));
837
838 test_ref_op!(pu + &lhs, pu + lhs.clone());
839 test_ref_op!(pu - &lhs, pu - lhs.clone());
840 test_ref_op!(pu * &lhs, pu * lhs.clone());
841 test_ref_op!(pu / &lhs, pu / lhs.clone());
842
843 test_ref_op!(&lhs + pi, lhs.clone() + pi);
844 test_ref_op!(&lhs - pi, lhs.clone() - pi);
845 test_ref_op!(&lhs * pi, lhs.clone() * pi);
846 test_ref_op!(&lhs / pi, lhs.clone() / pi);
847 test_ref_op!(&lhs << pi, lhs.clone() << pi);
848 test_ref_op!(&lhs >> pi, lhs.clone() >> pi);
849 test_ref_op!((&lhs).pow(pi), lhs.clone().pow(pi));
850
851 test_ref_op!(pi + &lhs, pi + lhs.clone());
852 test_ref_op!(pi - &lhs, pi - lhs.clone());
853 test_ref_op!(pi * &lhs, pi * lhs.clone());
854 test_ref_op!(pi / &lhs, pi / lhs.clone());
855
856 test_ref_op!((&lhs).pow(ps), lhs.clone().pow(ps));
857 test_ref_op!((&lhs).pow(pd), lhs.clone().pow(pd));
858
859 float::free_cache(FreeCache::All);
860 }
861
862 macro_rules! check_others {
863 (&$list:expr, $against:expr) => {
864 for op in &$list {
865 let cop = Complex::with_val(150, op);
866 for b in &$against {
867 assert!(same(b.clone() + op, b.clone() + &cop));
868 assert!(same(op + b.clone(), cop.clone() + b));
869 assert!(same(b.clone() - op, b.clone() - &cop));
870 assert!(same(op - b.clone(), cop.clone() - b));
871 if b.real().is_finite() && b.imag().is_finite() {
872 assert!(same(b.clone() * op, b.clone() * &cop));
873 assert!(same(op * b.clone(), cop.clone() * b));
874 if *op != 0 {
875 assert!(same(b.clone() / op, b.clone() / &cop));
876 }
877 }
878 }
879 }
880 };
881 ($list:expr, $against:expr, $zero:expr) => {
882 for op in $list {
883 let cop = Complex::with_val(150, *op);
884 for b in &$against {
885 assert!(same(b.clone() + *op, b.clone() + &cop));
886 assert!(same(*op + b.clone(), cop.clone() + b));
887 assert!(same(b.clone() - *op, b.clone() - &cop));
888 assert!(same(*op - b.clone(), cop.clone() - b));
889 if b.real().is_finite() && b.imag().is_finite() {
890 assert!(same(b.clone() * *op, b.clone() * &cop));
891 assert!(same(*op * b.clone(), cop.clone() * b));
892 if *op != $zero {
893 assert!(same(b.clone() / *op, b.clone() / &cop));
894 }
895 if *b != 0i32 {
896 assert!(same(*op / b.clone(), cop.clone() / b));
897 }
898 }
899 }
900 }
901 };
902 }
903
904 #[test]
905 fn check_arith_others() {
906 use crate::tests::{
907 F32, F64, I8, I16, I32, I64, I128, ISIZE, U8, U16, U32, U64, U128, USIZE,
908 };
909 let large = [
910 Complex::with_val(20, (Special::Zero, 1.0)),
911 Complex::with_val(20, (Special::NegZero, 1.0)),
912 Complex::with_val(20, (Special::Infinity, 1.0)),
913 Complex::with_val(20, (Special::NegInfinity, 1.0)),
914 Complex::with_val(20, (Special::Nan, 1.0)),
915 Complex::with_val(20, (1, 1.0)),
916 Complex::with_val(20, (-1, 1.0)),
917 Complex::with_val(20, (999_999e100, 1.0)),
918 Complex::with_val(20, (999_999e-100, 1.0)),
919 Complex::with_val(20, (-999_999e100, 1.0)),
920 Complex::with_val(20, (-999_999e-100, 1.0)),
921 ];
922 #[cfg(feature = "integer")]
923 let z = [
924 Integer::from(0),
925 Integer::from(1),
926 Integer::from(-1),
927 Integer::from_str("-1000000000000").unwrap(),
928 Integer::from_str("1000000000000").unwrap(),
929 ];
930 #[cfg(feature = "rational")]
931 let q = [
932 Rational::from(0),
933 Rational::from(1),
934 Rational::from(-1),
935 Rational::from_str("-1000000000000/33333333333").unwrap(),
936 Rational::from_str("1000000000000/33333333333").unwrap(),
937 ];
938 let f = [
939 Float::with_val(20, 0.0),
940 Float::with_val(20, 1.0),
941 Float::with_val(20, -1.0),
942 Float::with_val(20, 12.5),
943 Float::with_val(20, 12.5) << 10000,
944 Float::with_val(20, Special::Infinity),
945 ];
946
947 let mut against = large
948 .iter()
949 .cloned()
950 .chain(U32.iter().map(|&x| Complex::with_val(20, x)))
951 .chain(I32.iter().map(|&x| Complex::with_val(20, x)))
952 .chain(U64.iter().map(|&x| Complex::with_val(20, x)))
953 .chain(I64.iter().map(|&x| Complex::with_val(20, x)))
954 .chain(U128.iter().map(|&x| Complex::with_val(20, x)))
955 .chain(I128.iter().map(|&x| Complex::with_val(20, x)))
956 .chain(USIZE.iter().map(|&x| Complex::with_val(20, x)))
957 .chain(ISIZE.iter().map(|&x| Complex::with_val(20, x)))
958 .chain(F32.iter().map(|&x| Complex::with_val(20, x)))
959 .chain(F64.iter().map(|&x| Complex::with_val(20, x)))
960 .collect::<Vec<Complex>>();
961 #[cfg(feature = "integer")]
962 against.extend(z.iter().map(|x| Complex::with_val(20, x)));
963 #[cfg(feature = "rational")]
964 against.extend(q.iter().map(|x| Complex::with_val(20, x)));
965 against.extend(f.iter().map(|x| Complex::with_val(20, x)));
966
967 check_others!(I8, against, 0);
968 check_others!(I16, against, 0);
969 check_others!(I32, against, 0);
970 check_others!(I64, against, 0);
971 check_others!(I128, against, 0);
972 check_others!(ISIZE, against, 0);
973 check_others!(U8, against, 0);
974 check_others!(U16, against, 0);
975 check_others!(U32, against, 0);
976 check_others!(U64, against, 0);
977 check_others!(U128, against, 0);
978 check_others!(USIZE, against, 0);
979 check_others!(F32, against, 0.0);
980 check_others!(F64, against, 0.0);
981 #[cfg(feature = "integer")]
982 check_others!(&z, against);
983 #[cfg(feature = "rational")]
984 check_others!(&q, against);
985 check_others!(&f, against);
986
987 float::free_cache(FreeCache::All);
988 }
989
990 macro_rules! check_pow {
991 ($list:expr, $against:expr) => {
992 for op in $list {
993 let cop = Complex::with_val(150, *op);
994 for b in &$against {
995 assert!(same(b.clone().pow(*op), b.clone().pow(&cop)));
996 assert!(same(op.pow(b.clone()), cop.clone().pow(b)));
997 }
998 }
999 };
1000 }
1001
1002 #[test]
1003 fn check_pow() {
1004 use crate::tests::{F32, I32};
1005 let large = [
1006 Complex::with_val(20, (Special::Zero, 1.0)),
1007 Complex::with_val(20, (Special::NegZero, 1.0)),
1008 Complex::with_val(20, (Special::Infinity, 1.0)),
1009 Complex::with_val(20, (Special::NegInfinity, 1.0)),
1010 Complex::with_val(20, (Special::Nan, 1.0)),
1011 Complex::with_val(20, (1, 1.0)),
1012 Complex::with_val(20, (-1, 1.0)),
1013 Complex::with_val(20, (999_999e100, 1.0)),
1014 Complex::with_val(20, (999_999e-100, 1.0)),
1015 Complex::with_val(20, (-999_999e100, 1.0)),
1016 Complex::with_val(20, (-999_999e-100, 1.0)),
1017 ];
1018 let f = [
1019 Float::with_val(20, 0.0),
1020 Float::with_val(20, 1.0),
1021 Float::with_val(20, -1.0),
1022 Float::with_val(20, 12.5),
1023 Float::with_val(20, 12.5) << 10000,
1024 Float::with_val(20, Special::Infinity),
1025 ];
1026
1027 let against = large
1028 .iter()
1029 .cloned()
1030 .chain(I32.iter().map(|&x| Complex::with_val(20, x)))
1031 .chain(F32.iter().map(|&x| Complex::with_val(20, x)))
1032 .chain(f.iter().map(|x| Complex::with_val(20, x)))
1033 .collect::<Vec<Complex>>();
1034
1035 check_pow!(&[-1001i32, -1, 0, 1, 1001], against);
1036 check_pow!(&[0u32, 1, 1001], against);
1037 check_pow!(
1038 &[
1039 0.0,
1040 1.0,
1041 -1.0,
1042 1000.5,
1043 f64::NAN,
1044 f64::INFINITY,
1045 f64::NEG_INFINITY
1046 ],
1047 against
1048 );
1049
1050 float::free_cache(FreeCache::All);
1051 }
1052
1053 #[cfg(feature = "integer")]
1054 #[test]
1055 fn check_pow_int() {
1056 use crate::tests::{F32, I32};
1057 let large = [
1058 Complex::with_val(20, (Special::Zero, 1.0)),
1059 Complex::with_val(20, (Special::NegZero, 1.0)),
1060 Complex::with_val(20, (Special::Infinity, 1.0)),
1061 Complex::with_val(20, (Special::NegInfinity, 1.0)),
1062 Complex::with_val(20, (Special::Nan, 1.0)),
1063 Complex::with_val(20, (1, 1.0)),
1064 Complex::with_val(20, (-1, 1.0)),
1065 Complex::with_val(20, (999_999e100, 1.0)),
1066 Complex::with_val(20, (999_999e-100, 1.0)),
1067 Complex::with_val(20, (-999_999e100, 1.0)),
1068 Complex::with_val(20, (-999_999e-100, 1.0)),
1069 ];
1070 let f = [
1071 Float::with_val(20, 0.0),
1072 Float::with_val(20, 1.0),
1073 Float::with_val(20, -1.0),
1074 Float::with_val(20, 12.5),
1075 Float::with_val(20, 12.5) << 10000,
1076 Float::with_val(20, Special::Infinity),
1077 ];
1078 let i = [
1079 Integer::from(0),
1080 Integer::from(1),
1081 Integer::from(-1),
1082 Integer::from(12),
1083 Integer::from(-12),
1084 Integer::from(12) << 100,
1085 ];
1086
1087 let comp = large
1088 .iter()
1089 .cloned()
1090 .chain(I32.iter().map(|&x| Complex::with_val(20, x)))
1091 .chain(F32.iter().map(|&x| Complex::with_val(20, x)))
1092 .chain(f.iter().map(|x| Complex::with_val(20, x)))
1093 .chain(i.iter().map(|x| Complex::with_val(20, x)))
1094 .collect::<Vec<Complex>>();
1095
1096 for a in &comp {
1097 for b in &i {
1098 let b_as_c = Complex::with_val(150, b);
1099 assert!(same(a.clone().pow(b), a.clone().pow(b_as_c)));
1100 }
1101 }
1102
1103 float::free_cache(FreeCache::All);
1104 }
1105
1106 #[test]
1107 fn check_shift_u_s() {
1108 let c = &Complex::with_val(53, (13.75, -1.92e-10));
1109
1110 assert_eq!(c.clone() << 10u32, c.clone() << 10i32);
1111 assert_eq!(c.clone() << 10u32, c.clone() >> -10i32);
1112 assert_eq!(c.clone() >> 10u32, c.clone() >> 10i32);
1113 assert_eq!(c.clone() >> 10u32, c.clone() << -10i32);
1114
1115 assert_eq!(c.clone() << 10u32, c.clone() << 10usize);
1116 assert_eq!(c.clone() << 10u32, c.clone() << 10isize);
1117 assert_eq!(c.clone() << 10u32, c.clone() >> -10isize);
1118 assert_eq!(c.clone() >> 10u32, c.clone() >> 10usize);
1119 assert_eq!(c.clone() >> 10u32, c.clone() >> 10isize);
1120 assert_eq!(c.clone() >> 10u32, c.clone() << -10isize);
1121 }
1122}