Skip to main content

rug/rational/
arith.rs

1// Copyright © 2016–2026 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::xmpq;
18use crate::ext::xmpq::OptRational;
19use crate::integer::MiniInteger;
20use crate::integer::arith::AsLong;
21use crate::ops::{AddFrom, DivFrom, MulFrom, NegAssign, Pow, PowAssign, SubFrom};
22use crate::rational::MiniRational;
23use crate::{Assign, Complete, Integer, Rational};
24use az::{CheckedAs, CheckedCast};
25use core::ffi::{c_long, c_ulong};
26use core::iter::{Product, Sum};
27use core::ops::{
28    Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Shl, ShlAssign, Shr, ShrAssign, Sub,
29    SubAssign,
30};
31
32arith_unary! {
33    Rational;
34    xmpq::neg;
35    Neg { neg }
36    NegAssign { neg_assign }
37    NegIncomplete
38}
39arith_binary_self! {
40    Rational;
41    xmpq::add;
42    Add { add }
43    AddAssign { add_assign }
44    AddFrom { add_from }
45    AddIncomplete;
46    rhs_has_more_alloc
47}
48arith_binary_self! {
49    Rational;
50    xmpq::sub;
51    Sub { sub }
52    SubAssign { sub_assign }
53    SubFrom { sub_from }
54    SubIncomplete;
55    rhs_has_more_alloc
56}
57arith_binary_self! {
58    Rational;
59    xmpq::mul;
60    Mul { mul }
61    MulAssign { mul_assign }
62    MulFrom { mul_from }
63    MulIncomplete;
64    rhs_has_more_alloc
65}
66arith_binary_self! {
67    Rational;
68    xmpq::div;
69    Div { div }
70    DivAssign { div_assign }
71    DivFrom { div_from }
72    DivIncomplete;
73    rhs_has_more_alloc
74}
75
76arith_mini_commut! {
77    Rational;
78    Add { add }
79    AddAssign { add_assign }
80    AddFrom { add_from }
81    MiniRational;
82    AddMiniIncomplete, AddOwnedMiniIncomplete
83}
84arith_mini_noncommut! {
85    Rational;
86    Sub { sub }
87    SubAssign { sub_assign }
88    SubFrom { sub_from }
89    MiniRational;
90    SubMiniIncomplete, SubOwnedMiniIncomplete;
91    SubFromMiniIncomplete, SubFromOwnedMiniIncomplete
92}
93arith_mini_commut! {
94    Rational;
95    Mul { mul }
96    MulAssign { mul_assign }
97    MulFrom { mul_from }
98    MiniRational;
99    MulMiniIncomplete, MulOwnedMiniIncomplete
100}
101arith_mini_noncommut! {
102    Rational;
103    Div { div }
104    DivAssign { div_assign }
105    DivFrom { div_from }
106    MiniRational;
107    DivMiniIncomplete, DivOwnedMiniIncomplete;
108    DivFromMiniIncomplete, DivFromOwnedMiniIncomplete
109}
110
111arith_commut! {
112    Rational;
113    xmpq::add_z;
114    Add { add }
115    AddAssign { add_assign }
116    AddFrom { add_from }
117    Integer;
118    AddIntegerIncomplete, AddOwnedIntegerIncomplete
119}
120arith_noncommut! {
121    Rational;
122    xmpq::sub_z;
123    xmpq::z_sub;
124    Sub { sub }
125    SubAssign { sub_assign }
126    SubFrom { sub_from }
127    Integer;
128    SubIntegerIncomplete, SubOwnedIntegerIncomplete;
129    SubFromIntegerIncomplete, SubFromOwnedIntegerIncomplete
130}
131arith_commut! {
132    Rational;
133    xmpq::mul_z;
134    Mul { mul }
135    MulAssign { mul_assign }
136    MulFrom { mul_from }
137    Integer;
138    MulIntegerIncomplete, MulOwnedIntegerIncomplete
139}
140arith_noncommut! {
141    Rational;
142    xmpq::div_z;
143    xmpq::z_div;
144    Div { div }
145    DivAssign { div_assign }
146    DivFrom { div_from }
147    Integer;
148    DivIntegerIncomplete, DivOwnedIntegerIncomplete;
149    DivFromIntegerIncomplete, DivFromOwnedIntegerIncomplete
150}
151
152arith_prim_commut! {
153    Rational;
154    PrimOps::add;
155    Add { add }
156    AddAssign { add_assign }
157    AddFrom { add_from }
158    i8, AddI8Incomplete;
159    i16, AddI16Incomplete;
160    i32, AddI32Incomplete;
161    i64, AddI64Incomplete;
162    i128, AddI128Incomplete;
163    isize, AddIsizeIncomplete;
164    u8, AddU8Incomplete;
165    u16, AddU16Incomplete;
166    u32, AddU32Incomplete;
167    u64, AddU64Incomplete;
168    u128, AddU128Incomplete;
169    usize, AddUsizeIncomplete;
170}
171arith_prim_noncommut! {
172    Rational;
173    PrimOps::sub, PrimOps::sub_from;
174    Sub { sub }
175    SubAssign { sub_assign }
176    SubFrom { sub_from }
177    i8, SubI8Incomplete, SubFromI8Incomplete;
178    i16, SubI16Incomplete, SubFromI16Incomplete;
179    i32, SubI32Incomplete, SubFromI32Incomplete;
180    i64, SubI64Incomplete, SubFromI64Incomplete;
181    i128, SubI128Incomplete, SubFromI128Incomplete;
182    isize, SubIsizeIncomplete, SubFromIsizeIncomplete;
183    u8, SubU8Incomplete, SubFromU8Incomplete;
184    u16, SubU16Incomplete, SubFromU16Incomplete;
185    u32, SubU32Incomplete, SubFromU32Incomplete;
186    u64, SubU64Incomplete, SubFromU64Incomplete;
187    u128, SubU128Incomplete, SubFromU128Incomplete;
188    usize, SubUsizeIncomplete, SubFromUsizeIncomplete;
189}
190arith_prim_commut! {
191    Rational;
192    PrimOps::mul;
193    Mul { mul }
194    MulAssign { mul_assign }
195    MulFrom { mul_from }
196    i8, MulI8Incomplete;
197    i16, MulI16Incomplete;
198    i32, MulI32Incomplete;
199    i64, MulI64Incomplete;
200    i128, MulI128Incomplete;
201    isize, MulIsizeIncomplete;
202    u8, MulU8Incomplete;
203    u16, MulU16Incomplete;
204    u32, MulU32Incomplete;
205    u64, MulU64Incomplete;
206    u128, MulU128Incomplete;
207    usize, MulUsizeIncomplete;
208}
209arith_prim_noncommut! {
210    Rational;
211    PrimOps::div, PrimOps::div_from;
212    Div { div }
213    DivAssign { div_assign }
214    DivFrom { div_from }
215    i8, DivI8Incomplete, DivFromI8Incomplete;
216    i16, DivI16Incomplete, DivFromI16Incomplete;
217    i32, DivI32Incomplete, DivFromI32Incomplete;
218    i64, DivI64Incomplete, DivFromI64Incomplete;
219    i128, DivI128Incomplete, DivFromI128Incomplete;
220    isize, DivIsizeIncomplete, DivFromIsizeIncomplete;
221    u8, DivU8Incomplete, DivFromU8Incomplete;
222    u16, DivU16Incomplete, DivFromU16Incomplete;
223    u32, DivU32Incomplete, DivFromU32Incomplete;
224    u64, DivU64Incomplete, DivFromU64Incomplete;
225    u128, DivU128Incomplete, DivFromU128Incomplete;
226    usize, DivUsizeIncomplete, DivFromUsizeIncomplete;
227}
228
229arith_prim! {
230    Rational;
231    xmpq::shl_i32;
232    Shl { shl }
233    ShlAssign { shl_assign }
234    i32, ShlI32Incomplete;
235}
236arith_prim! {
237    Rational;
238    xmpq::shr_i32;
239    Shr { shr }
240    ShrAssign { shr_assign }
241    i32, ShrI32Incomplete;
242}
243arith_prim! {
244    Rational;
245    xmpq::shl_u32;
246    Shl { shl }
247    ShlAssign { shl_assign }
248    u32, ShlU32Incomplete;
249}
250arith_prim! {
251    Rational;
252    xmpq::shr_u32;
253    Shr { shr }
254    ShrAssign { shr_assign }
255    u32, ShrU32Incomplete;
256}
257arith_prim! {
258    Rational;
259    xmpq::shl_isize;
260    Shl { shl }
261    ShlAssign { shl_assign }
262    isize, ShlIsizeIncomplete;
263}
264arith_prim! {
265    Rational;
266    xmpq::shr_isize;
267    Shr { shr }
268    ShrAssign { shr_assign }
269    isize, ShrIsizeIncomplete;
270}
271arith_prim! {
272    Rational;
273    xmpq::shl_usize;
274    Shl { shl }
275    ShlAssign { shl_assign }
276    usize, ShlUsizeIncomplete;
277}
278arith_prim! {
279    Rational;
280    xmpq::shr_usize;
281    Shr { shr }
282    ShrAssign { shr_assign }
283    usize, ShrUsizeIncomplete;
284}
285arith_prim! {
286    Rational;
287    xmpq::pow_i32;
288    Pow { pow }
289    PowAssign { pow_assign }
290    i32, PowI32Incomplete;
291}
292arith_prim! {
293    Rational;
294    xmpq::pow_u32;
295    Pow { pow }
296    PowAssign { pow_assign }
297    u32, PowU32Incomplete;
298}
299
300trait PrimOps<Long>: AsLong {
301    fn add<O: OptRational>(rop: &mut Rational, op1: O, op2: Self);
302    fn sub<O: OptRational>(rop: &mut Rational, op1: O, op2: Self);
303    fn sub_from<O: OptRational>(rop: &mut Rational, op1: Self, op2: O);
304    fn mul<O: OptRational>(rop: &mut Rational, op1: O, op2: Self);
305    fn div<O: OptRational>(rop: &mut Rational, op1: O, op2: Self);
306    fn div_from<O: OptRational>(rop: &mut Rational, op1: Self, op2: O);
307}
308
309macro_rules! forward {
310    (fn $fn:ident() -> $deleg_long:path, $deleg:path) => {
311        #[inline]
312        fn $fn<O: OptRational>(rop: &mut Rational, op1: O, op2: Self) {
313            if let Some(op2) = op2.checked_as() {
314                $deleg_long(rop, op1, op2);
315            } else {
316                let mut small: MiniInteger = op2.into();
317                $deleg(rop, op1, &*small.borrow_excl());
318            }
319        }
320    };
321}
322macro_rules! reverse {
323    (fn $fn:ident() -> $deleg_long:path, $deleg:path) => {
324        #[inline]
325        fn $fn<O: OptRational>(rop: &mut Rational, op1: Self, op2: O) {
326            if let Some(op1) = op1.checked_as() {
327                $deleg_long(rop, op1, op2);
328            } else {
329                let mut small: MiniInteger = op1.into();
330                $deleg(rop, &*small.borrow_excl(), op2);
331            }
332        }
333    };
334}
335
336impl<T> PrimOps<c_long> for T
337where
338    T: AsLong<Long = c_long> + CheckedCast<c_long> + Into<MiniInteger>,
339{
340    forward! { fn add() -> xmpq::add_si, xmpq::add_z }
341    forward! { fn sub() -> xmpq::sub_si, xmpq::sub_z }
342    reverse! { fn sub_from() -> xmpq::si_sub, xmpq::z_sub }
343    forward! { fn mul() -> xmpq::mul_si, xmpq::mul_z }
344    forward! { fn div() -> xmpq::div_si, xmpq::div_z }
345    reverse! { fn div_from() -> xmpq::si_div, xmpq::z_div }
346}
347
348impl<T> PrimOps<c_ulong> for T
349where
350    T: AsLong<Long = c_ulong> + CheckedCast<c_ulong> + Into<MiniInteger>,
351{
352    forward! { fn add() -> xmpq::add_ui, xmpq::add_z }
353    forward! { fn sub() -> xmpq::sub_ui, xmpq::sub_z }
354    reverse! { fn sub_from() -> xmpq::ui_sub, xmpq::z_sub }
355    forward! { fn mul() -> xmpq::mul_ui, xmpq::mul_z }
356    forward! { fn div() -> xmpq::div_ui, xmpq::div_z }
357    reverse! { fn div_from() -> xmpq::ui_div, xmpq::z_div }
358}
359
360impl<T> Sum<T> for Rational
361where
362    Rational: AddAssign<T>,
363{
364    fn sum<I>(iter: I) -> Rational
365    where
366        I: Iterator<Item = T>,
367    {
368        let mut ret = Rational::new();
369        for i in iter {
370            ret.add_assign(i);
371        }
372        ret
373    }
374}
375
376impl<T> Product<T> for Rational
377where
378    Rational: MulAssign<T>,
379{
380    fn product<I>(iter: I) -> Rational
381    where
382        I: Iterator<Item = T>,
383    {
384        let mut ret = Rational::from(1);
385        for i in iter {
386            ret.mul_assign(i);
387        }
388        ret
389    }
390}
391
392#[inline]
393fn rhs_has_more_alloc(lhs: &Rational, rhs: &Rational) -> bool {
394    // This can overflow:
395    //     lhs.num.alloc + lhs.den.alloc < rhs.num.alloc + rhs.den.alloc
396    // Since all alloc are non-negative signed integers (c_int), this
397    // cannot overflow:
398    //     lhs.num.alloc - rhs.den.alloc < rhs.num.alloc - lhs.den.alloc
399    lhs.numer().inner().alloc - rhs.denom().inner().alloc
400        < rhs.numer().inner().alloc - lhs.denom().inner().alloc
401}
402
403#[cfg(test)]
404mod tests {
405    use crate::ops::Pow;
406    use crate::ops::{AddFrom, SubFrom};
407    use crate::rational::MiniRational;
408    use crate::{Assign, Complete, Integer, Rational};
409
410    macro_rules! test_ref_op {
411        ($first:expr, $second:expr) => {
412            assert_eq!(
413                Rational::from($first),
414                $second,
415                "({}) != ({})",
416                stringify!($first),
417                stringify!($second)
418            );
419        };
420    }
421
422    #[test]
423    fn check_ref_op() {
424        let lhs = Rational::from((-13, 27));
425        let rhs = Rational::from((15, 101));
426        let pu = 30_u32;
427        let pi = -15_i32;
428        test_ref_op!(-&lhs, -lhs.clone());
429        test_ref_op!(&lhs + &rhs, lhs.clone() + &rhs);
430        test_ref_op!(&lhs - &rhs, lhs.clone() - &rhs);
431        test_ref_op!(&lhs * &rhs, lhs.clone() * &rhs);
432        test_ref_op!(&lhs / &rhs, lhs.clone() / &rhs);
433
434        test_ref_op!(&lhs << pu, lhs.clone() << pu);
435        test_ref_op!(&lhs >> pu, lhs.clone() >> pu);
436        test_ref_op!((&lhs).pow(pu), lhs.clone().pow(pu));
437
438        test_ref_op!(&lhs << pi, lhs.clone() << pi);
439        test_ref_op!(&lhs >> pi, lhs.clone() >> pi);
440        test_ref_op!((&lhs).pow(pi), lhs.clone().pow(pi));
441    }
442
443    macro_rules! test_numer_denom {
444        ($first:expr, $second:expr) => {{
445            let a = $first;
446            let b = $second;
447            assert_eq!(
448                a.numer(),
449                b.numer(),
450                "({}).numer() != ({}).numer()",
451                stringify!($first),
452                stringify!($second)
453            );
454            assert_eq!(
455                a.denom(),
456                b.denom(),
457                "({}).denom() != ({}).denom()",
458                stringify!($first),
459                stringify!($second)
460            );
461        }};
462    }
463
464    #[test]
465    fn check_arith_int() {
466        let r = &Rational::from((-15, 128));
467        let zero = &Integer::new();
468        let minus_100 = &Integer::from(-100);
469
470        test_numer_denom!(r.clone() + zero, r + Rational::from(zero));
471        test_numer_denom!(r.clone() - zero, r - Rational::from(zero));
472        test_numer_denom!(r.clone() * zero, r * Rational::from(zero));
473        test_numer_denom!(r.clone() + minus_100, r + Rational::from(minus_100));
474        test_numer_denom!(r.clone() - minus_100, r - Rational::from(minus_100));
475        test_numer_denom!(r.clone() * minus_100, r * Rational::from(minus_100));
476        test_numer_denom!(r.clone() / minus_100, r / Rational::from(minus_100));
477
478        test_numer_denom!(zero + r.clone(), Rational::from(zero) + r);
479        test_numer_denom!(zero - r.clone(), Rational::from(zero) - r);
480        test_numer_denom!(zero * r.clone(), Rational::from(zero) * r);
481        test_numer_denom!(zero / r.clone(), Rational::from(zero) / r);
482        test_numer_denom!(minus_100 + r.clone(), Rational::from(minus_100) + r);
483        test_numer_denom!(minus_100 - r.clone(), Rational::from(minus_100) - r);
484        test_numer_denom!(minus_100 * r.clone(), Rational::from(minus_100) * r);
485        test_numer_denom!(minus_100 / r.clone(), Rational::from(minus_100) / r);
486    }
487
488    #[test]
489    fn check_neg_pow() {
490        let a = Rational::from((-12, 7));
491        let pow_pos = a.clone().pow(3i32);
492        assert_eq!(
493            pow_pos,
494            MiniRational::from(((-12i32).pow(3), 7i32.pow(3u32)))
495        );
496        let pow_neg = a.pow(-3i32);
497        assert_eq!(pow_neg, MiniRational::from(((-7i32).pow(3), 12i32.pow(3))));
498    }
499
500    macro_rules! check_u_s {
501        ($list:expr, $against:expr) => {
502            for &op in $list {
503                let rat_op = Rational::from(op);
504                for b in &$against {
505                    test_numer_denom!(b.clone() + op, b.clone() + &rat_op);
506                    test_numer_denom!(b.clone() - op, b.clone() - &rat_op);
507                    test_numer_denom!(b.clone() * op, b.clone() * &rat_op);
508                    if op != 0 {
509                        test_numer_denom!(b.clone() / op, b.clone() / &rat_op);
510                    }
511                    test_numer_denom!(op + b.clone(), rat_op.clone() + b);
512                    test_numer_denom!(op - b.clone(), rat_op.clone() - b);
513                    test_numer_denom!(op * b.clone(), rat_op.clone() * b);
514                    if !b.is_zero() {
515                        test_numer_denom!(op / b.clone(), rat_op.clone() / b);
516                    }
517                }
518            }
519        };
520    }
521
522    fn num_den<T>(s: &[T]) -> impl Iterator<Item = Rational> + '_
523    where
524        T: Copy + Eq + From<bool>,
525        Rational: From<(T, T)>,
526    {
527        let zero = T::from(false);
528        let one = T::from(true);
529        s.iter()
530            .map(move |&den| if den == zero { one } else { den })
531            .flat_map(move |den| s.iter().map(move |&num| Rational::from((num, den))))
532    }
533
534    #[test]
535    fn check_arith_u_s() {
536        use crate::tests::{I8, I16, I32, I64, I128, ISIZE, U8, U16, U32, U64, U128, USIZE};
537        let large = [(1, 3, 100), (-11, 5, 200), (33, 79, -150)];
538        let against = (large.iter().map(|&(n, d, s)| Rational::from((n, d)) << s))
539            .chain(num_den(I32))
540            .chain(num_den(U32))
541            .chain(num_den(I64))
542            .chain(num_den(U64))
543            .chain(num_den(I128))
544            .chain(num_den(U128))
545            .chain(num_den(ISIZE))
546            .chain(num_den(USIZE))
547            .collect::<Vec<Rational>>();
548
549        check_u_s!(I8, against);
550        check_u_s!(I16, against);
551        check_u_s!(I32, against);
552        check_u_s!(I64, against);
553        check_u_s!(I128, against);
554        check_u_s!(ISIZE, against);
555        check_u_s!(U8, against);
556        check_u_s!(U16, against);
557        check_u_s!(U32, against);
558        check_u_s!(U64, against);
559        check_u_s!(USIZE, against);
560    }
561
562    #[test]
563    #[allow(clippy::op_ref)]
564    fn check_mini_ops() {
565        let big = Rational::from((10, 3));
566        let mini = MiniRational::from((3, 2));
567        let mut bm = Rational::new();
568
569        // commutative
570        let sum = MiniRational::from((29, 6));
571        assert_eq!(big.clone() + mini, sum);
572        assert_eq!(big.clone() + &mini, sum);
573        assert_eq!((&big + mini).complete(), sum);
574        assert_eq!((&big + &mini).complete(), sum);
575
576        bm.assign(&big);
577        bm += mini;
578        assert_eq!(bm, sum);
579        bm.assign(&big);
580        bm += &mini;
581        assert_eq!(bm, sum);
582
583        assert_eq!(mini + big.clone(), sum);
584        assert_eq!(&mini + big.clone(), sum);
585        assert_eq!((mini + &big).complete(), sum);
586        assert_eq!((&mini + &big).complete(), sum);
587
588        bm.assign(&big);
589        bm.add_from(mini);
590        assert_eq!(bm, sum);
591        bm.assign(&big);
592        bm.add_from(&mini);
593        assert_eq!(bm, sum);
594
595        // non-commutative
596        let diff1 = MiniRational::from((11, 6));
597        assert_eq!(big.clone() - mini, diff1);
598        assert_eq!(big.clone() - &mini, diff1);
599        assert_eq!((&big - mini).complete(), diff1);
600        assert_eq!((&big - &mini).complete(), diff1);
601
602        bm.assign(&big);
603        bm -= mini;
604        assert_eq!(bm, diff1);
605        bm.assign(&big);
606        bm -= &mini;
607        assert_eq!(bm, diff1);
608
609        let diff2 = MiniRational::from((-11, 6));
610        assert_eq!(mini - big.clone(), diff2);
611        assert_eq!(&mini - big.clone(), diff2);
612        assert_eq!((mini - &big).complete(), diff2);
613        assert_eq!((&mini - &big).complete(), diff2);
614
615        bm.assign(&big);
616        bm.sub_from(mini);
617        assert_eq!(bm, diff2);
618        bm.assign(&big);
619        bm.sub_from(&mini);
620        assert_eq!(bm, diff2);
621    }
622
623    #[test]
624    fn check_shift_u_s() {
625        let pos = &(Rational::from((13, 7)) >> 100u32);
626        let neg = &(Rational::from((19, 101)) << 200u32);
627
628        assert_eq!(pos.clone() << 10u32, pos.clone() << 10i32);
629        assert_eq!(pos.clone() << 10u32, pos.clone() >> -10i32);
630        assert_eq!(pos.clone() >> 10u32, pos.clone() >> 10i32);
631        assert_eq!(pos.clone() >> 10u32, pos.clone() << -10i32);
632
633        assert_eq!(neg.clone() << 10u32, neg.clone() << 10i32);
634        assert_eq!(neg.clone() << 10u32, neg.clone() >> -10i32);
635        assert_eq!(neg.clone() >> 10u32, neg.clone() >> 10i32);
636        assert_eq!(neg.clone() >> 10u32, neg.clone() << -10i32);
637
638        assert_eq!(pos.clone() << 10u32, pos.clone() << 10usize);
639        assert_eq!(pos.clone() << 10u32, pos.clone() << 10isize);
640        assert_eq!(pos.clone() << 10u32, pos.clone() >> -10isize);
641        assert_eq!(pos.clone() >> 10u32, pos.clone() >> 10usize);
642        assert_eq!(pos.clone() >> 10u32, pos.clone() >> 10isize);
643        assert_eq!(pos.clone() >> 10u32, pos.clone() << -10isize);
644
645        assert_eq!(neg.clone() << 10u32, neg.clone() << 10usize);
646        assert_eq!(neg.clone() << 10u32, neg.clone() << 10isize);
647        assert_eq!(neg.clone() << 10u32, neg.clone() >> -10isize);
648        assert_eq!(neg.clone() >> 10u32, neg.clone() >> 10usize);
649        assert_eq!(neg.clone() >> 10u32, neg.clone() >> 10isize);
650        assert_eq!(neg.clone() >> 10u32, neg.clone() << -10isize);
651    }
652}