numera/number/integer/pz/
integer.rs

1// numera::number::integer::pz::integer
2//
3//!
4//
5
6use crate::number::{
7    integer::{pz::*, Integer},
8    traits::ConstOne,
9};
10use devela::convert::az::CheckedAs;
11
12#[cfg(not(feature = "std"))]
13use crate::all::is_prime;
14#[cfg(feature = "std")]
15use crate::all::is_prime_sieve;
16
17macro_rules! impl_nonzero_integer {
18    // $t:
19    // $inner:
20    (many: $($t:ident, $inner:ident),+) => {
21        $( impl_nonzero_integer![$t, $inner]; )+
22    };
23    ($t:ident, $inner:ident) => {
24        /// Methods for all integers
25        impl $t {
26            /// Returns `true` if this integer is even.
27            #[inline]
28            #[must_use]
29            pub const fn is_even(&self) -> bool {
30                self.0.get() & 1 == 0
31            }
32            /// Returns `true` if this integer is odd.
33            #[inline]
34            #[must_use]
35            pub const fn is_odd(&self) -> bool {
36                !self.is_even()
37            }
38
39            /// Returns `true` if this integer is a multiple of the `other`.
40            #[inline]
41            #[must_use]
42            pub const fn is_multiple_of(&self, other: &Self) -> bool {
43                self.0.get() % other.0.get() == 0
44            }
45            /// Returns `true` if this integer is a divisor of the `other`.
46            #[inline]
47            #[must_use]
48            pub const fn is_divisor_of(&self, other: &Self) -> bool {
49                other.is_multiple_of(self)
50            }
51
52            /// Returns `true` if `self` and `other` are relative primes,
53            /// which means they have only 1 as their only common divisor.
54            ///
55            /// # Notation
56            /// $a \perp b$.
57            #[inline]
58            #[must_use]
59            pub const fn is_coprime(&self, other: &Self) -> bool {
60                self.gcd(other).0.get() == Self::ONE.0.get()
61            }
62
63            /// Returns the number of digits in base 10.
64            #[inline]
65            #[must_use]
66            pub const fn digits(&self) -> usize {
67                self.0.ilog10() as usize + 1
68            }
69        }
70
71        /// Methods for non-negative integers
72        impl $t {
73            /// Returns `Some(true)` if this integer is prime, `Some(false)` if it's not
74            /// prime, or `None` if it can not be determined.
75            ///
76            /// Returns `None` if this integer can't be represented as a [`usize`],
77            /// or as a [`u32`] in `no-std`.
78            #[inline]
79            pub fn is_prime(&self) -> Option<bool> {
80                #[cfg(feature = "std")]
81                return Some(is_prime_sieve((self.0.get()).checked_as::<usize>()?));
82                #[cfg(not(feature = "std"))]
83                return Some(is_prime((self.0.get()).checked_as::<u32>()?));
84            }
85
86            /// Calculates the *Greatest Common Divisor* of this integer and `other`.
87            #[inline]
88            #[must_use]
89            pub const fn gcd(&self, other: &Self) -> Self {
90                let (mut a, mut b) = (self.0.get(), other.0.get());
91                while b != 0 {
92                    let temp = b;
93                    b = a % b;
94                    a = temp;
95                }
96                #[cfg(feature = "safe")]
97                if let Ok(n0z) = $t::new(a) {
98                    n0z
99                } else {
100                    unreachable![]
101                }
102
103                #[cfg(not(feature = "safe"))]
104                // SAFETY: when self & other are not 0, the result can't be 0
105                return unsafe { $t::new_unchecked(a) };
106            }
107
108            /// Calculates the *Lowest Common Multiple* of this integer and `other`.
109            #[inline]
110            #[must_use]
111            pub const fn lcm(&self, other: &Self) -> Self {
112                let lcm = self.0.get() * other.0.get() / self.gcd(other).0.get();
113
114                #[cfg(feature = "safe")]
115                if let Ok(n0z) = $t::new(lcm) {
116                    n0z
117                } else {
118                    unreachable![]
119                }
120                #[cfg(not(feature = "safe"))]
121                // SAFETY: when self & other are not 0, the result can't be 0
122                return unsafe { $t::new_unchecked(lcm) };
123            }
124        }
125        impl Integer for $t {
126            #[inline]
127            fn integer_is_even(&self) -> bool {
128                self.is_even()
129            }
130            #[inline]
131            fn integer_is_multiple_of(&self, other: &Self) -> bool {
132                self.is_multiple_of(other)
133            }
134            #[inline]
135            fn integer_is_prime(&self) -> Option<bool> {
136                self.is_prime()
137            }
138            #[inline]
139            fn integer_gcd(&self, other: &Self) -> Option<Self> {
140                Some(self.gcd(other))
141            }
142            #[inline]
143            fn integer_lcm(&self, other: &Self) -> Option<Self> {
144                Some(self.lcm(other))
145            }
146            #[inline]
147            fn integer_digits(&self) -> usize {
148                self.digits()
149            }
150        }
151    };
152}
153
154impl_nonzero_integer![
155    many: PositiveInteger8,
156    NonZeroU8,
157    PositiveInteger16,
158    NonZeroU16,
159    PositiveInteger32,
160    NonZeroU32,
161    PositiveInteger64,
162    NonZeroU64,
163    PositiveInteger128,
164    NonZeroU128
165];
166
167#[cfg(test)]
168mod tests {
169    use crate::error::NumeraResult;
170    use crate::number::integer::pz::*;
171
172    #[test]
173    fn pz_lcm_gcd() -> NumeraResult<()> {
174        let pz10 = Pz32::new(10)?;
175        let pz15 = Pz32::new(15)?;
176
177        assert_eq![Pz32::new(30)?, pz10.lcm(&pz15)];
178        assert_eq![Pz32::new(5)?, pz10.gcd(&pz15)];
179        Ok(())
180    }
181}