rug/integer/
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
17use crate::ext::xmpz;
18use crate::ext::xmpz::OptInteger;
19use crate::integer::MiniInteger;
20use crate::ops::{
21    AddFrom, BitAndFrom, BitOrFrom, BitXorFrom, DivFrom, MulFrom, NegAssign, NotAssign, Pow,
22    PowAssign, RemFrom, SubFrom,
23};
24use crate::{Assign, Complete, Integer};
25use az::{CheckedAs, CheckedCast};
26use core::ffi::{c_long, c_ulong};
27use core::iter::{Product, Sum};
28use core::ops::{
29    Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
30    Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
31};
32
33arith_unary! {
34    Integer;
35    xmpz::neg;
36    Neg { neg }
37    NegAssign { neg_assign }
38    NegIncomplete
39}
40arith_binary_self! {
41    Integer;
42    xmpz::add;
43    Add { add }
44    AddAssign { add_assign }
45    AddFrom { add_from }
46    AddIncomplete;
47    rhs_has_more_alloc
48}
49arith_binary_self! {
50    Integer;
51    xmpz::sub;
52    Sub { sub }
53    SubAssign { sub_assign }
54    SubFrom { sub_from }
55    SubIncomplete;
56    rhs_has_more_alloc
57}
58arith_binary_self! {
59    Integer;
60    xmpz::mul;
61    Mul { mul }
62    MulAssign { mul_assign }
63    MulFrom { mul_from }
64    MulIncomplete;
65    rhs_has_more_alloc
66}
67arith_binary_self! {
68    Integer;
69    xmpz::tdiv_q;
70    Div { div }
71    DivAssign { div_assign }
72    DivFrom { div_from }
73    DivIncomplete;
74    rhs_has_more_alloc
75}
76arith_binary_self! {
77    Integer;
78    xmpz::tdiv_r;
79    Rem { rem }
80    RemAssign { rem_assign }
81    RemFrom { rem_from }
82    RemIncomplete;
83    rhs_has_more_alloc
84}
85arith_unary! {
86    Integer;
87    xmpz::com;
88    Not { not }
89    NotAssign { not_assign }
90    NotIncomplete
91}
92arith_binary_self! {
93    Integer;
94    xmpz::and;
95    BitAnd { bitand }
96    BitAndAssign { bitand_assign }
97    BitAndFrom { bitand_from }
98    BitAndIncomplete;
99    rhs_has_more_alloc
100}
101arith_binary_self! {
102    Integer;
103    xmpz::ior;
104    BitOr { bitor }
105    BitOrAssign { bitor_assign }
106    BitOrFrom { bitor_from }
107    BitOrIncomplete;
108    rhs_has_more_alloc
109}
110arith_binary_self! {
111    Integer;
112    xmpz::xor;
113    BitXor { bitxor }
114    BitXorAssign { bitxor_assign }
115    BitXorFrom { bitxor_from }
116    BitXorIncomplete;
117    rhs_has_more_alloc
118}
119
120arith_prim_commut! {
121    Integer;
122    PrimOps::add;
123    Add { add }
124    AddAssign { add_assign }
125    AddFrom { add_from }
126    i8, AddI8Incomplete;
127    i16, AddI16Incomplete;
128    i32, AddI32Incomplete;
129    i64, AddI64Incomplete;
130    i128, AddI128Incomplete;
131    isize, AddIsizeIncomplete;
132    u8, AddU8Incomplete;
133    u16, AddU16Incomplete;
134    u32, AddU32Incomplete;
135    u64, AddU64Incomplete;
136    u128, AddU128Incomplete;
137    usize, AddUsizeIncomplete;
138}
139arith_prim_noncommut! {
140    Integer;
141    PrimOps::sub, PrimOps::sub_from;
142    Sub { sub }
143    SubAssign { sub_assign }
144    SubFrom { sub_from }
145    i8, SubI8Incomplete, SubFromI8Incomplete;
146    i16, SubI16Incomplete, SubFromI16Incomplete;
147    i32, SubI32Incomplete, SubFromI32Incomplete;
148    i64, SubI64Incomplete, SubFromI64Incomplete;
149    i128, SubI128Incomplete, SubFromI128Incomplete;
150    isize, SubIsizeIncomplete, SubFromIsizeIncomplete;
151    u8, SubU8Incomplete, SubFromU8Incomplete;
152    u16, SubU16Incomplete, SubFromU16Incomplete;
153    u32, SubU32Incomplete, SubFromU32Incomplete;
154    u64, SubU64Incomplete, SubFromU64Incomplete;
155    u128, SubU128Incomplete, SubFromU128Incomplete;
156    usize, SubUsizeIncomplete, SubFromUsizeIncomplete;
157}
158arith_prim_commut! {
159    Integer;
160    PrimOps::mul;
161    Mul { mul }
162    MulAssign { mul_assign }
163    MulFrom { mul_from }
164    i8, MulI8Incomplete;
165    i16, MulI16Incomplete;
166    i32, MulI32Incomplete;
167    i64, MulI64Incomplete;
168    i128, MulI128Incomplete;
169    isize, MulIsizeIncomplete;
170    u8, MulU8Incomplete;
171    u16, MulU16Incomplete;
172    u32, MulU32Incomplete;
173    u64, MulU64Incomplete;
174    u128, MulU128Incomplete;
175    usize, MulUsizeIncomplete;
176}
177arith_prim_noncommut! {
178    Integer;
179    PrimOps::div, PrimOps::div_from;
180    Div { div }
181    DivAssign { div_assign }
182    DivFrom { div_from }
183    i8, DivI8Incomplete, DivFromI8Incomplete;
184    i16, DivI16Incomplete, DivFromI16Incomplete;
185    i32, DivI32Incomplete, DivFromI32Incomplete;
186    i64, DivI64Incomplete, DivFromI64Incomplete;
187    i128, DivI128Incomplete, DivFromI128Incomplete;
188    isize, DivIsizeIncomplete, DivFromIsizeIncomplete;
189    u8, DivU8Incomplete, DivFromU8Incomplete;
190    u16, DivU16Incomplete, DivFromU16Incomplete;
191    u32, DivU32Incomplete, DivFromU32Incomplete;
192    u64, DivU64Incomplete, DivFromU64Incomplete;
193    u128, DivU128Incomplete, DivFromU128Incomplete;
194    usize, DivUsizeIncomplete, DivFromUsizeIncomplete;
195}
196arith_prim_noncommut! {
197    Integer;
198    PrimOps::rem, PrimOps::rem_from;
199    Rem { rem }
200    RemAssign { rem_assign }
201    RemFrom { rem_from }
202    i8, RemI8Incomplete, RemFromI8Incomplete;
203    i16, RemI16Incomplete, RemFromI16Incomplete;
204    i32, RemI32Incomplete, RemFromI32Incomplete;
205    i64, RemI64Incomplete, RemFromI64Incomplete;
206    i128, RemI128Incomplete, RemFromI128Incomplete;
207    isize, RemIsizeIncomplete, RemFromIsizeIncomplete;
208    u8, RemU8Incomplete, RemFromU8Incomplete;
209    u16, RemU16Incomplete, RemFromU16Incomplete;
210    u32, RemU32Incomplete, RemFromU32Incomplete;
211    u64, RemU64Incomplete, RemFromU64Incomplete;
212    u128, RemU128Incomplete, RemFromU128Incomplete;
213    usize, RemUsizeIncomplete, RemFromUsizeIncomplete;
214}
215arith_prim_commut! {
216    Integer;
217    PrimOps::and;
218    BitAnd { bitand }
219    BitAndAssign { bitand_assign }
220    BitAndFrom { bitand_from }
221    i8, BitAndI8Incomplete;
222    i16, BitAndI16Incomplete;
223    i32, BitAndI32Incomplete;
224    i64, BitAndI64Incomplete;
225    i128, BitAndI128Incomplete;
226    isize, BitAndIsizeIncomplete;
227    u8, BitAndU8Incomplete;
228    u16, BitAndU16Incomplete;
229    u32, BitAndU32Incomplete;
230    u64, BitAndU64Incomplete;
231    u128, BitAndU128Incomplete;
232    usize, BitAndUsizeIncomplete;
233}
234arith_prim_commut! {
235    Integer;
236    PrimOps::ior;
237    BitOr { bitor }
238    BitOrAssign { bitor_assign }
239    BitOrFrom { bitor_from }
240    i8, BitOrI8Incomplete;
241    i16, BitOrI16Incomplete;
242    i32, BitOrI32Incomplete;
243    i64, BitOrI64Incomplete;
244    i128, BitOrI128Incomplete;
245    isize, BitOrIsizeIncomplete;
246    u8, BitOrU8Incomplete;
247    u16, BitOrU16Incomplete;
248    u32, BitOrU32Incomplete;
249    u64, BitOrU64Incomplete;
250    u128, BitOrU128Incomplete;
251    usize, BitOrUsizeIncomplete;
252}
253arith_prim_commut! {
254    Integer;
255    PrimOps::xor;
256    BitXor { bitxor }
257    BitXorAssign { bitxor_assign }
258    BitXorFrom { bitxor_from }
259    i8, BitXorI8Incomplete;
260    i16, BitXorI16Incomplete;
261    i32, BitXorI32Incomplete;
262    i64, BitXorI64Incomplete;
263    i128, BitXorI128Incomplete;
264    isize, BitXorIsizeIncomplete;
265    u8, BitXorU8Incomplete;
266    u16, BitXorU16Incomplete;
267    u32, BitXorU32Incomplete;
268    u64, BitXorU64Incomplete;
269    u128, BitXorU128Incomplete;
270    usize, BitXorUsizeIncomplete;
271}
272
273arith_prim! {
274    Integer;
275    xmpz::shl_i32;
276    Shl { shl }
277    ShlAssign { shl_assign }
278    i32, ShlI32Incomplete;
279}
280arith_prim! {
281    Integer;
282    xmpz::shr_i32;
283    Shr { shr }
284    ShrAssign { shr_assign }
285    i32, ShrI32Incomplete;
286}
287arith_prim! {
288    Integer;
289    xmpz::shl_u32;
290    Shl { shl }
291    ShlAssign { shl_assign }
292    u32, ShlU32Incomplete;
293}
294arith_prim! {
295    Integer;
296    xmpz::shr_u32;
297    Shr { shr }
298    ShrAssign { shr_assign }
299    u32, ShrU32Incomplete;
300}
301arith_prim! {
302    Integer;
303    xmpz::shl_isize;
304    Shl { shl }
305    ShlAssign { shl_assign }
306    isize, ShlIsizeIncomplete;
307}
308arith_prim! {
309    Integer;
310    xmpz::shr_isize;
311    Shr { shr }
312    ShrAssign { shr_assign }
313    isize, ShrIsizeIncomplete;
314}
315arith_prim! {
316    Integer;
317    xmpz::shl_usize;
318    Shl { shl }
319    ShlAssign { shl_assign }
320    usize, ShlUsizeIncomplete;
321}
322arith_prim! {
323    Integer;
324    xmpz::shr_usize;
325    Shr { shr }
326    ShrAssign { shr_assign }
327    usize, ShrUsizeIncomplete;
328}
329arith_prim! {
330    Integer;
331    xmpz::pow_u32;
332    Pow { pow }
333    PowAssign { pow_assign }
334    u32, PowU32Incomplete;
335}
336
337mul_op_commut! {
338    Integer;
339    xmpz::addmul;
340    Add { add }
341    AddAssign { add_assign }
342    AddFrom { add_from }
343    MulIncomplete, AddMulIncomplete;
344}
345mul_op_noncommut! {
346    Integer;
347    xmpz::submul, xmpz::mulsub;
348    Sub { sub }
349    SubAssign { sub_assign }
350    SubFrom { sub_from }
351    MulIncomplete, SubMulIncomplete, SubMulFromIncomplete;
352}
353mul_op_commut! {
354    Integer;
355    PrimOps::addmul;
356    Add { add }
357    AddAssign { add_assign }
358    AddFrom { add_from }
359    MulI8Incomplete, AddMulI8Incomplete;
360    MulI16Incomplete, AddMulI16Incomplete;
361    MulI32Incomplete, AddMulI32Incomplete;
362    MulI64Incomplete, AddMulI64Incomplete;
363    MulI128Incomplete, AddMulI128Incomplete;
364    MulIsizeIncomplete, AddMulIsizeIncomplete;
365    MulU8Incomplete, AddMulU8Incomplete;
366    MulU16Incomplete, AddMulU16Incomplete;
367    MulU32Incomplete, AddMulU32Incomplete;
368    MulU64Incomplete, AddMulU64Incomplete;
369    MulU128Incomplete, AddMulU128Incomplete;
370    MulUsizeIncomplete, AddMulUsizeIncomplete;
371}
372mul_op_noncommut! {
373    Integer;
374    PrimOps::submul, PrimOps::mulsub;
375    Sub { sub }
376    SubAssign { sub_assign }
377    SubFrom { sub_from }
378    MulI8Incomplete, SubMulI8Incomplete, SubMulFromI8Incomplete;
379    MulI16Incomplete, SubMulI16Incomplete, SubMulFromI16Incomplete;
380    MulI32Incomplete, SubMulI32Incomplete, SubMulFromI32Incomplete;
381    MulI64Incomplete, SubMulI64Incomplete, SubMulFromI64Incomplete;
382    MulI128Incomplete, SubMulI128Incomplete, SubMulFromI128Incomplete;
383    MulIsizeIncomplete, SubMulIsizeIncomplete, SubMulFromIsizeIncomplete;
384    MulU8Incomplete, SubMulU8Incomplete, SubMulFromU8Incomplete;
385    MulU16Incomplete, SubMulU16Incomplete, SubMulFromU16Incomplete;
386    MulU32Incomplete, SubMulU32Incomplete, SubMulFromU32Incomplete;
387    MulU64Incomplete, SubMulU64Incomplete, SubMulFromU64Incomplete;
388    MulU128Incomplete, SubMulU128Incomplete, SubMulFromU128Incomplete;
389    MulUsizeIncomplete, SubMulUsizeIncomplete, SubMulFromUsizeIncomplete;
390}
391
392trait PrimOps<Long>: AsLong {
393    fn add<O: OptInteger>(rop: &mut Integer, op1: O, op2: Self);
394    fn sub<O: OptInteger>(rop: &mut Integer, op1: O, op2: Self);
395    fn sub_from<O: OptInteger>(rop: &mut Integer, op1: Self, op2: O);
396    fn mul<O: OptInteger>(rop: &mut Integer, op1: O, op2: Self);
397    fn div<O: OptInteger>(rop: &mut Integer, op1: O, op2: Self);
398    fn div_from<O: OptInteger>(rop: &mut Integer, op1: Self, op2: O);
399    fn rem<O: OptInteger>(rop: &mut Integer, op1: O, op2: Self);
400    fn rem_from<O: OptInteger>(rop: &mut Integer, op1: Self, op2: O);
401    fn and<O: OptInteger>(rop: &mut Integer, op1: O, op2: Self);
402    fn ior<O: OptInteger>(rop: &mut Integer, op1: O, op2: Self);
403    fn xor<O: OptInteger>(rop: &mut Integer, op1: O, op2: Self);
404    fn addmul(rop: &mut Integer, op1: &Integer, op2: Self);
405    fn submul(rop: &mut Integer, op1: &Integer, op2: Self);
406    fn mulsub(rop: &mut Integer, op1: &Integer, op2: Self);
407}
408
409pub trait AsLong: Copy {
410    type Long;
411}
412
413macro_rules! as_long {
414    ($Long:ty: $($Prim:ty)*) => { $(
415        impl AsLong for $Prim {
416            type Long = $Long;
417        }
418    )* }
419}
420
421as_long! { c_long: i8 i16 i32 i64 i128 isize }
422as_long! { c_ulong: u8 u16 u32 u64 u128 usize }
423
424macro_rules! forward {
425    (fn $fn:ident() -> $deleg_long:path, $deleg:path) => {
426        #[inline]
427        fn $fn<O: OptInteger>(rop: &mut Integer, op1: O, op2: Self) {
428            if let Some(op2) = op2.checked_as() {
429                $deleg_long(rop, op1, op2);
430            } else {
431                let mut small: MiniInteger = op2.into();
432                $deleg(rop, op1, small.borrow_excl());
433            }
434        }
435    };
436}
437macro_rules! reverse {
438    (fn $fn:ident() -> $deleg_long:path, $deleg:path) => {
439        #[inline]
440        fn $fn<O: OptInteger>(rop: &mut Integer, op1: Self, op2: O) {
441            if let Some(op1) = op1.checked_as() {
442                $deleg_long(rop, op1, op2);
443            } else {
444                let mut small: MiniInteger = op1.into();
445                $deleg(rop, small.borrow_excl(), op2);
446            }
447        }
448    };
449}
450
451impl<T> PrimOps<c_long> for T
452where
453    T: AsLong<Long = c_long> + CheckedCast<c_long> + Into<MiniInteger>,
454{
455    forward! { fn add() -> xmpz::add_si, xmpz::add }
456    forward! { fn sub() -> xmpz::sub_si, xmpz::sub }
457    reverse! { fn sub_from() -> xmpz::si_sub, xmpz::sub }
458    forward! { fn mul() -> xmpz::mul_si, xmpz::mul }
459    forward! { fn div() -> xmpz::tdiv_q_si, xmpz::tdiv_q }
460    reverse! { fn div_from() -> xmpz::si_tdiv_q, xmpz::tdiv_q }
461    forward! { fn rem() -> xmpz::tdiv_r_si, xmpz::tdiv_r }
462    reverse! { fn rem_from() -> xmpz::si_tdiv_r, xmpz::tdiv_r }
463    forward! { fn and() -> xmpz::and_si, xmpz::and }
464    forward! { fn ior() -> xmpz::ior_si, xmpz::ior }
465    forward! { fn xor() -> xmpz::xor_si, xmpz::xor }
466
467    #[inline]
468    fn addmul(rop: &mut Integer, op1: &Integer, op2: Self) {
469        if let Some(op2) = op2.checked_as() {
470            xmpz::addmul_si(rop, op1, op2);
471        } else {
472            let mut small: MiniInteger = op2.into();
473            xmpz::addmul(rop, op1, small.borrow_excl());
474        }
475    }
476
477    #[inline]
478    fn submul(rop: &mut Integer, op1: &Integer, op2: Self) {
479        if let Some(op2) = op2.checked_as() {
480            xmpz::submul_si(rop, op1, op2);
481        } else {
482            let mut small: MiniInteger = op2.into();
483            xmpz::submul(rop, op1, small.borrow_excl());
484        }
485    }
486
487    #[inline]
488    fn mulsub(rop: &mut Integer, op1: &Integer, op2: Self) {
489        if let Some(op2) = op2.checked_as() {
490            xmpz::mulsub_si(rop, op1, op2);
491        } else {
492            let mut small: MiniInteger = op2.into();
493            xmpz::mulsub(rop, op1, small.borrow_excl());
494        }
495    }
496}
497
498impl<T> PrimOps<c_ulong> for T
499where
500    T: AsLong<Long = c_ulong> + CheckedCast<c_ulong> + Into<MiniInteger>,
501{
502    forward! { fn add() -> xmpz::add_ui, xmpz::add }
503    forward! { fn sub() -> xmpz::sub_ui, xmpz::sub }
504    reverse! { fn sub_from() -> xmpz::ui_sub, xmpz::sub }
505    forward! { fn mul() -> xmpz::mul_ui, xmpz::mul }
506    forward! { fn div() -> xmpz::tdiv_q_ui, xmpz::tdiv_q }
507    reverse! { fn div_from() -> xmpz::ui_tdiv_q, xmpz::tdiv_q }
508    forward! { fn rem() -> xmpz::tdiv_r_ui, xmpz::tdiv_r }
509    reverse! { fn rem_from() -> xmpz::ui_tdiv_r, xmpz::tdiv_r }
510    forward! { fn and() -> xmpz::and_ui, xmpz::and }
511    forward! { fn ior() -> xmpz::ior_ui, xmpz::ior }
512    forward! { fn xor() -> xmpz::xor_ui, xmpz::xor }
513
514    #[inline]
515    fn addmul(rop: &mut Integer, op1: &Integer, op2: Self) {
516        if let Some(op2) = op2.checked_as() {
517            xmpz::addmul_ui(rop, op1, op2);
518        } else {
519            let mut small: MiniInteger = op2.into();
520            xmpz::addmul(rop, op1, small.borrow_excl());
521        }
522    }
523
524    #[inline]
525    fn submul(rop: &mut Integer, op1: &Integer, op2: Self) {
526        if let Some(op2) = op2.checked_as() {
527            xmpz::submul_ui(rop, op1, op2);
528        } else {
529            let mut small: MiniInteger = op2.into();
530            xmpz::submul(rop, op1, small.borrow_excl());
531        }
532    }
533
534    #[inline]
535    fn mulsub(rop: &mut Integer, op1: &Integer, op2: Self) {
536        if let Some(op2) = op2.checked_as() {
537            xmpz::mulsub_ui(rop, op1, op2);
538        } else {
539            let mut small: MiniInteger = op2.into();
540            xmpz::mulsub(rop, op1, small.borrow_excl());
541        }
542    }
543}
544
545impl<T> Sum<T> for Integer
546where
547    Integer: AddAssign<T>,
548{
549    fn sum<I>(iter: I) -> Integer
550    where
551        I: Iterator<Item = T>,
552    {
553        let mut ret = Integer::new();
554        for i in iter {
555            ret.add_assign(i);
556        }
557        ret
558    }
559}
560
561impl<T> Product<T> for Integer
562where
563    Integer: MulAssign<T>,
564{
565    fn product<I>(iter: I) -> Integer
566    where
567        I: Iterator<Item = T>,
568    {
569        let mut ret = Integer::from(1);
570        for i in iter {
571            ret.mul_assign(i);
572        }
573        ret
574    }
575}
576
577#[inline]
578fn rhs_has_more_alloc(lhs: &Integer, rhs: &Integer) -> bool {
579    lhs.inner().alloc < rhs.inner().alloc
580}
581
582#[cfg(test)]
583mod tests {
584    use crate::Integer;
585    use crate::ops::{AddFrom, Pow, SubFrom};
586    use core::ops::{AddAssign, SubAssign};
587
588    macro_rules! test_op {
589        ($lhs:ident $op:tt $rhs:ident) => {
590            let ans = $lhs.clone() $op $rhs.clone();
591            assert_eq!(ans, $lhs.clone() $op $rhs);
592            assert_eq!(ans, $lhs $op $rhs.clone());
593            assert_eq!(ans, Integer::from($lhs $op $rhs));
594        };
595    }
596
597    #[test]
598    fn check_arith() {
599        use crate::tests::{I32, I64, I128, ISIZE, U32, U64, U128, USIZE};
600        let large = [(1, 100), (-11, 200), (33, 150)];
601        let all = (large.iter().map(|&(n, s)| Integer::from(n) << s))
602            .chain(U32.iter().map(|&x| Integer::from(x)))
603            .chain(I32.iter().map(|&x| Integer::from(x)))
604            .chain(U64.iter().map(|&x| Integer::from(x)))
605            .chain(I64.iter().map(|&x| Integer::from(x)))
606            .chain(U128.iter().map(|&x| Integer::from(x)))
607            .chain(I128.iter().map(|&x| Integer::from(x)))
608            .chain(USIZE.iter().map(|&x| Integer::from(x)))
609            .chain(ISIZE.iter().map(|&x| Integer::from(x)))
610            .collect::<Vec<Integer>>();
611
612        for l in &all {
613            for r in &all {
614                test_op!(l + r);
615                test_op!(l - r);
616                test_op!(l * r);
617                if !r.is_zero() {
618                    test_op!(l / r);
619                }
620                test_op!(l & r);
621                test_op!(l | r);
622                test_op!(l ^ r);
623            }
624        }
625    }
626
627    macro_rules! check_u_s {
628        ($list:expr, $against:expr) => {
629            for &op in $list {
630                let iop = Integer::from(op);
631                for b in &$against {
632                    assert_eq!(b.clone() + op, b.clone() + &iop);
633                    assert_eq!(b.clone() - op, b.clone() - &iop);
634                    assert_eq!(b.clone() * op, b.clone() * &iop);
635                    if op != 0 {
636                        assert_eq!(b.clone() / op, b.clone() / &iop);
637                        assert_eq!(b.clone() % op, b.clone() % &iop);
638                    }
639                    assert_eq!(b.clone() & op, b.clone() & &iop);
640                    assert_eq!(b.clone() | op, b.clone() | &iop);
641                    assert_eq!(b.clone() ^ op, b.clone() ^ &iop);
642                    assert_eq!(op + b.clone(), iop.clone() + b);
643                    assert_eq!(op - b.clone(), iop.clone() - b);
644                    assert_eq!(op * b.clone(), iop.clone() * b);
645                    if !b.is_zero() {
646                        assert_eq!(op / b.clone(), iop.clone() / b);
647                        assert_eq!(op % b.clone(), iop.clone() % b);
648                    }
649                    assert_eq!(op & b.clone(), iop.clone() & b);
650                    assert_eq!(op | b.clone(), iop.clone() | b);
651                    assert_eq!(op ^ b.clone(), iop.clone() ^ b);
652                }
653            }
654        };
655    }
656
657    #[test]
658    fn check_arith_u_s() {
659        use crate::tests::{I8, I16, I32, I64, I128, ISIZE, U8, U16, U32, U64, U128, USIZE};
660        let large = [(1, 100), (-11, 200), (33, 150)];
661        let against = (large.iter().map(|&(n, s)| Integer::from(n) << s))
662            .chain(U32.iter().map(|&x| Integer::from(x)))
663            .chain(I32.iter().map(|&x| Integer::from(x)))
664            .chain(U64.iter().map(|&x| Integer::from(x)))
665            .chain(I64.iter().map(|&x| Integer::from(x)))
666            .chain(U128.iter().map(|&x| Integer::from(x)))
667            .chain(I128.iter().map(|&x| Integer::from(x)))
668            .chain(USIZE.iter().map(|&x| Integer::from(x)))
669            .chain(ISIZE.iter().map(|&x| Integer::from(x)))
670            .collect::<Vec<Integer>>();
671
672        check_u_s!(I8, against);
673        check_u_s!(I16, against);
674        check_u_s!(I32, against);
675        check_u_s!(I64, against);
676        check_u_s!(I128, against);
677        check_u_s!(ISIZE, against);
678        check_u_s!(U8, against);
679        check_u_s!(U16, against);
680        check_u_s!(U32, against);
681        check_u_s!(U64, against);
682        check_u_s!(U128, against);
683        check_u_s!(USIZE, against);
684    }
685
686    macro_rules! test_ref_op {
687        ($first:expr, $second:expr) => {
688            assert_eq!(
689                Integer::from($first),
690                $second,
691                "({}) != ({})",
692                stringify!($first),
693                stringify!($second)
694            );
695        };
696    }
697
698    #[test]
699    fn check_ref_op() {
700        let lhs = &Integer::from(0x00ff);
701        let rhs = &Integer::from(0x0f0f);
702        let pu = 30_u32;
703        let pi = -15_i32;
704        test_ref_op!(-lhs, -lhs.clone());
705        test_ref_op!(lhs + rhs, lhs.clone() + rhs);
706        test_ref_op!(lhs - rhs, lhs.clone() - rhs);
707        test_ref_op!(lhs * rhs, lhs.clone() * rhs);
708        test_ref_op!(lhs / rhs, lhs.clone() / rhs);
709        test_ref_op!(lhs % rhs, lhs.clone() % rhs);
710        test_ref_op!(!lhs, !lhs.clone());
711        test_ref_op!(lhs & rhs, lhs.clone() & rhs);
712        test_ref_op!(lhs | rhs, lhs.clone() | rhs);
713        test_ref_op!(lhs ^ rhs, lhs.clone() ^ rhs);
714
715        test_ref_op!(lhs + pu, lhs.clone() + pu);
716        test_ref_op!(lhs - pu, lhs.clone() - pu);
717        test_ref_op!(lhs * pu, lhs.clone() * pu);
718        test_ref_op!(lhs / pu, lhs.clone() / pu);
719        test_ref_op!(lhs % pu, lhs.clone() % pu);
720        test_ref_op!(lhs & pu, lhs.clone() & pu);
721        test_ref_op!(lhs | pu, lhs.clone() | pu);
722        test_ref_op!(lhs ^ pu, lhs.clone() ^ pu);
723        test_ref_op!(lhs << pu, lhs.clone() << pu);
724        test_ref_op!(lhs >> pu, lhs.clone() >> pu);
725        test_ref_op!(lhs.pow(pu), lhs.clone().pow(pu));
726
727        test_ref_op!(lhs + pi, lhs.clone() + pi);
728        test_ref_op!(lhs - pi, lhs.clone() - pi);
729        test_ref_op!(lhs * pi, lhs.clone() * pi);
730        test_ref_op!(lhs / pi, lhs.clone() / pi);
731        test_ref_op!(lhs % pi, lhs.clone() % pi);
732        test_ref_op!(lhs & pi, lhs.clone() & pi);
733        test_ref_op!(lhs | pi, lhs.clone() | pi);
734        test_ref_op!(lhs ^ pi, lhs.clone() ^ pi);
735        test_ref_op!(lhs << pi, lhs.clone() << pi);
736        test_ref_op!(lhs >> pi, lhs.clone() >> pi);
737
738        test_ref_op!(pu + lhs, pu + lhs.clone());
739        test_ref_op!(pu - lhs, pu - lhs.clone());
740        test_ref_op!(pu * lhs, pu * lhs.clone());
741        test_ref_op!(pu / lhs, pu / lhs.clone());
742        test_ref_op!(pu % lhs, pu % lhs.clone());
743        test_ref_op!(pu & lhs, pu & lhs.clone());
744        test_ref_op!(pu | lhs, pu | lhs.clone());
745        test_ref_op!(pu ^ lhs, pu ^ lhs.clone());
746
747        test_ref_op!(pi + lhs, pi + lhs.clone());
748        test_ref_op!(pi - lhs, pi - lhs.clone());
749        test_ref_op!(pi * lhs, pi * lhs.clone());
750        test_ref_op!(pi / lhs, pi / lhs.clone());
751        test_ref_op!(pi % lhs, pi % lhs.clone());
752        test_ref_op!(pi & lhs, pi & lhs.clone());
753        test_ref_op!(pi | lhs, pi | lhs.clone());
754        test_ref_op!(pi ^ lhs, pi ^ lhs.clone());
755    }
756
757    #[test]
758    fn check_shift_u_s() {
759        let pos = &(Integer::from(11) << 100u32);
760        let neg = &(Integer::from(-33) << 50u32);
761
762        assert_eq!(pos.clone() << 10u32, pos.clone() << 10i32);
763        assert_eq!(pos.clone() << 10u32, pos.clone() >> -10i32);
764        assert_eq!(pos.clone() >> 10u32, pos.clone() >> 10i32);
765        assert_eq!(pos.clone() >> 10u32, pos.clone() << -10i32);
766
767        assert_eq!(neg.clone() << 10u32, neg.clone() << 10i32);
768        assert_eq!(neg.clone() << 10u32, neg.clone() >> -10i32);
769        assert_eq!(neg.clone() >> 10u32, neg.clone() >> 10i32);
770        assert_eq!(neg.clone() >> 10u32, neg.clone() << -10i32);
771
772        assert_eq!(pos.clone() << 10u32, pos.clone() << 10usize);
773        assert_eq!(pos.clone() << 10u32, pos.clone() << 10isize);
774        assert_eq!(pos.clone() << 10u32, pos.clone() >> -10isize);
775        assert_eq!(pos.clone() >> 10u32, pos.clone() >> 10usize);
776        assert_eq!(pos.clone() >> 10u32, pos.clone() >> 10isize);
777        assert_eq!(pos.clone() >> 10u32, pos.clone() << -10isize);
778
779        assert_eq!(neg.clone() << 10u32, neg.clone() << 10usize);
780        assert_eq!(neg.clone() << 10u32, neg.clone() << 10isize);
781        assert_eq!(neg.clone() << 10u32, neg.clone() >> -10isize);
782        assert_eq!(neg.clone() >> 10u32, neg.clone() >> 10usize);
783        assert_eq!(neg.clone() >> 10u32, neg.clone() >> 10isize);
784        assert_eq!(neg.clone() >> 10u32, neg.clone() << -10isize);
785
786        assert_eq!(pos.clone() << 10, Integer::from(11) << 110);
787        assert_eq!(pos.clone() << -100, pos.clone() >> 100);
788        assert_eq!(pos.clone() << -100, 11);
789        assert_eq!(neg.clone() << 10, neg.clone() >> -10);
790        assert_eq!(neg.clone() << 10, Integer::from(-33) << 60);
791        assert_eq!(neg.clone() << -100, neg.clone() >> 100);
792        assert_eq!(neg.clone() << -100, -1);
793    }
794
795    fn check_single_addmul<F, T>(i: &mut Integer, j: &mut i32, f: F, u: i32)
796    where
797        F: Fn() -> T,
798        Integer: AddAssign<T> + AddFrom<T>,
799    {
800        *i += f();
801        *j += u;
802        assert_eq!(i, j);
803        i.add_from(f());
804        j.add_from(u);
805        assert_eq!(i, j);
806    }
807
808    fn check_single_submul<F, T>(i: &mut Integer, j: &mut i32, f: F, u: i32)
809    where
810        F: Fn() -> T,
811        Integer: SubAssign<T> + SubFrom<T>,
812    {
813        *i -= f();
814        *j -= u;
815        assert_eq!(i, j);
816        i.sub_from(f());
817        j.sub_from(u);
818        assert_eq!(i, j);
819    }
820
821    #[test]
822    fn check_addmul() {
823        let mut i = Integer::from(10);
824        let mut j = 10i32;
825        let two = Integer::from(2);
826
827        check_single_addmul(&mut i, &mut j, || &two * &two, 2 * 2);
828        check_single_addmul(&mut i, &mut j, || &two * 12u32, 2 * 12);
829        check_single_addmul(&mut i, &mut j, || 13u32 * &two, 13 * 2);
830        check_single_addmul(&mut i, &mut j, || &two * 14i32, 2 * 14);
831        check_single_addmul(&mut i, &mut j, || 15i32 * &two, 15 * 2);
832        check_single_addmul(&mut i, &mut j, || &two * -16i32, 2 * -16);
833        check_single_addmul(&mut i, &mut j, || -17i32 * &two, -17 * 2);
834    }
835
836    #[test]
837    fn check_submul() {
838        let mut i = Integer::from(10);
839        let mut j = 10i32;
840        let two = Integer::from(2);
841
842        check_single_submul(&mut i, &mut j, || &two * &two, 2 * 2);
843        check_single_submul(&mut i, &mut j, || &two * 12u32, 2 * 12);
844        check_single_submul(&mut i, &mut j, || 13u32 * &two, 13 * 2);
845        check_single_submul(&mut i, &mut j, || &two * 14i32, 2 * 14);
846        check_single_submul(&mut i, &mut j, || 15i32 * &two, 15 * 2);
847        check_single_submul(&mut i, &mut j, || &two * -16i32, 2 * -16);
848        check_single_submul(&mut i, &mut j, || -17i32 * &two, -17 * 2);
849    }
850}