rug/complex/
arith.rs

1// Copyright © 2016–2025 Trevor Spiteri
2
3// This program is free software: you can redistribute it and/or modify it under
4// the terms of the GNU Lesser General Public License as published by the Free
5// Software Foundation, either version 3 of the License, or (at your option) any
6// later version.
7//
8// This program is distributed in the hope that it will be useful, but WITHOUT
9// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11// details.
12//
13// You should have received a copy of the GNU Lesser General Public License and
14// a copy of the GNU General Public License along with this program. If not, see
15// <https://www.gnu.org/licenses/>.
16
17#[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}