1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// numera::number::integer::z::ops::div_rem
//
//! Implement the division and remainder operations.
//
use crate::number::integer::*;
use devela::paste;
macro_rules! impl_integer_div_rem {
// impl Div and Rem ops together for multiple integer types
//
// # Args
// $t: integer base name. e.g. Integer
// $p: inner primitive base name. e.g. i
// $b: integer and primitive bitsize. e.g. 8
( $($t:ident + $p:ident + $b:literal, cast: $bcast:literal);+ ) => {
$(
impl_integer_div_rem![div_rem: $t + $p + $b];
)+
};
// impl the division + remainder operations together
(div_rem: $t:ident + $p:ident + $b:literal) => { paste! {
// helper function for the inner primitive
#[inline]
pub(crate) const fn [<div_rem_trunc_$p$b>](lhs: [<$p$b>], rhs: [<$p$b>]) -> ([<$p$b>], [<$p$b>]) {
(lhs / rhs, lhs % rhs)
}
/// # Division and remainder
impl [<$t$b>] {
/// Alias of [`div_rem_trunc`][Self#method.div_rem_trunc].
#[inline(always)]
pub const fn div_rem(self, rhs: [<$t$b>]) -> ([<$t$b>], [<$t$b>]) {
self.div_rem_trunc(rhs)
}
/// Returns the truncated (`quotient`, `remainder`).
///
/// # Panics
/// If `rhs` is 0 or if division results in overflow.
/// ```
/// # use numera::all::Z8;
/// assert_eq![Z8::new(7).div_rem_trunc(Z8::new(3)), (Z8::new(2), Z8::new(1))];
/// assert_eq![Z8::new(7).div_rem_trunc(Z8::new(-3)), (Z8::new(-2), Z8::new(1))];
/// assert_eq![Z8::new(-7).div_rem_trunc(Z8::new(3)), (Z8::new(-2), Z8::new(-1))];
/// assert_eq![Z8::new(-7).div_rem_trunc(Z8::new(-3)), (Z8::new(2), Z8::new(-1))];
/// ```
#[inline]
#[must_use]
pub const fn div_rem_trunc(self, rhs: [<$t$b>]) -> ([<$t$b>], [<$t$b>]) {
(self.div_trunc(rhs), self.rem_trunc(rhs))
}
/// Returns the euclidean (`quotient`, `remainder`).
///
/// # Panics
/// If `rhs` is 0 or if division results in overflow.
///
/// # Examples
/// ```
/// # use numera::all::Z8;
/// assert_eq![Z8::new(7).div_rem_euclid(Z8::new(3)), (Z8::new(2), Z8::new(1))];
/// assert_eq![Z8::new(7).div_rem_euclid(Z8::new(-3)), (Z8::new(-2), Z8::new(1))];
/// assert_eq![Z8::new(-7).div_rem_euclid(Z8::new(3)), (Z8::new(-3), Z8::new(2))];
/// assert_eq![Z8::new(-7).div_rem_euclid(Z8::new(-3)), (Z8::new(3), Z8::new(2))];
/// ```
pub const fn div_rem_euclid(self, rhs: [<$t$b>]) -> ([<$t$b>], [<$t$b>]) {
let (q, r) = [<div_rem_trunc_$p$b>](self.0, rhs.0);
if r < 0 {
if rhs.0 > 0 {
(Self(q - 1), Self(r + rhs.0))
} else {
(Self(q + 1), Self(r - rhs.0))
}
} else {
(Self(q), Self(r))
}
// NOTE: must use primitives because PartialOrd is not const
// let (q, r) = self.div_rem_trunc(rhs);
// if r < Self::ZERO {
// if rhs > Self::ZERO {
// (q - Self::ONE, r + rhs)
// } else {
// (q + Self::ONE, r - rhs)
// }
// } else {
// (q, r)
// }
}
/// Returns the ceiled (`quotient`, `remainder`).
///
/// # Panics
/// If `rhs` is 0 or if division results in overflow.
///
/// # Examples
/// ```
/// # use numera::all::Z8;
/// assert_eq![Z8::new(7).div_rem_ceil(Z8::new(3)), (Z8::new(3), Z8::new(-2))];
/// assert_eq![Z8::new(7).div_rem_ceil(Z8::new(-3)), (Z8::new(-2), Z8::new(1))];
/// assert_eq![Z8::new(-7).div_rem_ceil(Z8::new(3)), (Z8::new(-2), Z8::new(-1))];
/// assert_eq![Z8::new(-7).div_rem_ceil(Z8::new(-3)), (Z8::new(3), Z8::new(2))];
/// ```
pub const fn div_rem_ceil(self, rhs: [<$t$b>]) -> ([<$t$b>], [<$t$b>]) {
if self.0 > 0 && rhs.0 > 0 {
let (q, r) = [<div_rem_trunc_$p$b>]((self.0 - 1), rhs.0);
(Self(q + 1), Self(r - rhs.0 + 1))
} else if self.0 < 0 && rhs.0 < 0 {
let (q, r) = [<div_rem_trunc_$p$b>]((self.0 + 1), rhs.0);
(Self(q + 1), Self(r - rhs.0 - 1))
} else {
let (q, r) = [<div_rem_trunc_$p$b>](self.0, rhs.0);
(Self(q), Self(r))
}
}
/// Returns the floored (`quotient`, `remainder`).
///
/// # Panics
/// If `rhs` is 0 or if division results in overflow.
///
/// # Examples
/// ```
/// # use numera::all::Z8;
/// assert_eq![Z8::new(7).div_rem_floor(Z8::new(3)), (Z8::new(2), Z8::new(1))];
/// assert_eq![Z8::new(7).div_rem_floor(Z8::new(-3)), (Z8::new(-3), Z8::new(-2))];
/// assert_eq![Z8::new(-7).div_rem_floor(Z8::new(3)), (Z8::new(-3), Z8::new(2))];
/// assert_eq![Z8::new(-7).div_rem_floor(Z8::new(-3)), (Z8::new(2), Z8::new(-1))];
/// ```
pub const fn div_rem_floor(self, rhs: [<$t$b>]) -> ([<$t$b>], [<$t$b>]) {
if self.0 > 0 && rhs.0 < 0 {
let (q, r) = [<div_rem_trunc_$p$b>](self.0 - 1, rhs.0);
(Self(q - 1), Self(r + rhs.0 + 1))
} else if self.0 < 0 && rhs.0 > 0 {
let (q, r) = [<div_rem_trunc_$p$b>](self.0 + 1, rhs.0);
(Self(q - 1), Self(r + rhs.0 - 1))
} else {
let (q, r) = [<div_rem_trunc_$p$b>](self.0, rhs.0);
(Self(q), Self(r))
}
}
}
}};
}
impl_integer_div_rem![
Integer+i+8, cast:16;
Integer+i+16, cast:32;
Integer+i+32, cast:64;
Integer+i+64, cast:128;
Integer+i+128, cast:128
];