1use super::*;
2
3impl<
4 const N: u32,
5 const ES: u32,
6 Int: crate::Int,
7> Posit<N, ES, Int> {
8 #[inline]
10 pub(crate) unsafe fn add_kernel(x: Decoded<N, ES, Int>, y: Decoded<N, ES, Int>) -> (Decoded<N, ES, Int>, Int) {
11 let shift = x.exp - y.exp;
32 let (x, y) = if shift.is_positive() { (x, y) } else { (y, x) };
33 let shift = shift.abs().as_u32();
34 if shift >= Int::BITS { return (x, Int::ZERO)
38 };
39 let xfrac = x.frac;
40 let yfrac = y.frac >> shift;
41 let exp = x.exp;
42
43 let (frac, overflow) = xfrac.overflowing_add_shift(yfrac);
57 let exp = exp + overflow.into();
58 let sticky_overflow = (xfrac | yfrac) & overflow.into();
61
62 let underflow = unsafe { frac.leading_run_minus_one() };
78 let frac = frac << underflow as u32;
79 let exp = exp - Int::of_u32(underflow);
80 let true_shift = shift.checked_sub(underflow).unwrap_or(0); let recovered = y.frac.mask_lsb(shift) >> true_shift;
93 let sticky = y.frac.mask_lsb(true_shift);
94 let frac = frac | recovered;
95
96 (Decoded{frac, exp}, (sticky | sticky_overflow))
97 }
98
99 pub(crate) fn add(self, other: Self) -> Self {
100 let sum = self.0.wrapping_add(other.0);
101 if self == Self::NAR || other == Self::NAR {
102 Self::NAR
103 } else if sum == Int::ZERO || sum == self.0 || sum == other.0 {
104 Self(sum)
105 } else {
106 let a = unsafe { self.decode_regular() };
108 let b = unsafe { other.decode_regular() };
109 let (result, sticky) = unsafe { Self::add_kernel(a, b) };
111 unsafe { result.encode_regular_round(sticky) }
113 }
114 }
115
116 pub(crate) fn sub(self, other: Self) -> Self {
117 self.add(-other)
118 }
119}
120
121use core::ops::{Add, AddAssign, Sub, SubAssign};
122
123super::mk_ops!{Add, AddAssign, add, add_assign}
124super::mk_ops!{Sub, SubAssign, sub, sub_assign}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129
130 mod add {
131 use super::*;
132 use malachite::rational::Rational;
133
134 #[allow(dead_code)]
135 fn ops() {
136 let mut a = crate::p32::ONE;
137 let mut b = crate::p32::MINUS_ONE;
138 let _ = a + b;
139 let _ = &a + b;
140 let _ = a + &b;
141 let _ = &a + &b;
142 a += b;
143 b += &a;
144 }
145
146 fn is_correct_rounded<const N: u32, const ES: u32, Int: crate::Int>(
148 a: Posit<N, ES, Int>,
149 b: Posit<N, ES, Int>,
150 ) -> bool
151 where
152 Rational: TryFrom<Posit<N, ES, Int>>,
153 <Rational as TryFrom<Posit<N, ES, Int>>>::Error: core::fmt::Debug
154 {
155 let sum_posit = a + b;
156 if let (Ok(a), Ok(b)) = (Rational::try_from(a), Rational::try_from(b)) {
157 let sum_exact = a + b;
158 super::rational::is_correct_rounded(sum_exact, sum_posit)
159 } else {
160 sum_posit == Posit::<N, ES, Int>::NAR
161 }
162 }
163
164 #[test]
165 fn posit_10_0_exhaustive() {
166 for a in Posit::<10, 0, i16>::cases_exhaustive_all() {
167 for b in Posit::<10, 0, i16>::cases_exhaustive_all() {
168 assert!(is_correct_rounded(a, b), "{:?}: {:?}", a, b)
169 }
170 }
171 }
172
173 #[test]
174 fn posit_10_1_exhaustive() {
175 for a in Posit::<10, 1, i16>::cases_exhaustive_all() {
176 for b in Posit::<10, 1, i16>::cases_exhaustive_all() {
177 assert!(is_correct_rounded(a, b), "{:?}: {:?}", a, b)
178 }
179 }
180 }
181
182 #[test]
183 fn posit_10_2_exhaustive() {
184 for a in Posit::<10, 2, i16>::cases_exhaustive_all() {
185 for b in Posit::<10, 2, i16>::cases_exhaustive_all() {
186 assert!(is_correct_rounded(a, b), "{:?}: {:?}", a, b)
187 }
188 }
189 }
190
191 #[test]
192 fn posit_10_3_exhaustive() {
193 for a in Posit::<10, 3, i16>::cases_exhaustive_all() {
194 for b in Posit::<10, 3, i16>::cases_exhaustive_all() {
195 assert!(is_correct_rounded(a, b), "{:?}: {:?}", a, b)
196 }
197 }
198 }
199
200 #[test]
201 fn posit_8_0_exhaustive() {
202 for a in Posit::<8, 0, i8>::cases_exhaustive_all() {
203 for b in Posit::<8, 0, i8>::cases_exhaustive_all() {
204 assert!(is_correct_rounded(a, b), "{:?}: {:?}", a, b)
205 }
206 }
207 }
208
209 #[test]
210 fn p8_exhaustive() {
211 for a in crate::p8::cases_exhaustive_all() {
212 for b in crate::p8::cases_exhaustive_all() {
213 assert!(is_correct_rounded(a, b), "{:?}: {:?}", a, b)
214 }
215 }
216 }
217
218 use proptest::prelude::*;
219 const PROPTEST_CASES: u32 = if cfg!(debug_assertions) {0x1_0000} else {0x80_0000};
220 proptest!{
221 #![proptest_config(ProptestConfig::with_cases(PROPTEST_CASES))]
222
223 #[test]
224 fn p16_proptest(
225 a in crate::p16::cases_proptest(),
226 b in crate::p16::cases_proptest(),
227 ) {
228 assert!(is_correct_rounded(a, b), "{:?}: {:?}", a, b)
229 }
230
231 #[test]
232 fn p32_proptest(
233 a in crate::p32::cases_proptest(),
234 b in crate::p32::cases_proptest(),
235 ) {
236 assert!(is_correct_rounded(a, b), "{:?}: {:?}", a, b)
237 }
238
239 #[test]
240 fn p64_proptest(
241 a in crate::p64::cases_proptest(),
242 b in crate::p64::cases_proptest(),
243 ) {
244 assert!(is_correct_rounded(a, b), "{:?}: {:?}", a, b)
245 }
246 }
247
248 #[test]
249 fn posit_3_0_exhaustive() {
250 for a in Posit::<3, 0, i8>::cases_exhaustive_all() {
251 for b in Posit::<3, 0, i8>::cases_exhaustive_all() {
252 assert!(is_correct_rounded(a, b), "{:?}: {:?}", a, b)
253 }
254 }
255 }
256 #[test]
257 fn posit_4_0_exhaustive() {
258 for a in Posit::<4, 0, i8>::cases_exhaustive_all() {
259 for b in Posit::<4, 0, i8>::cases_exhaustive_all() {
260 assert!(is_correct_rounded(a, b), "{:?}: {:?}", a, b)
261 }
262 }
263 }
264 #[test]
265 fn posit_4_1_exhaustive() {
266 for a in Posit::<4, 1, i8>::cases_exhaustive_all() {
267 for b in Posit::<4, 1, i8>::cases_exhaustive_all() {
268 assert!(is_correct_rounded(a, b), "{:?}: {:?}", a, b)
269 }
270 }
271 }
272 }
273
274 mod sub {
275 use super::*;
276 use malachite::rational::Rational;
277
278 #[allow(dead_code)]
279 fn ops() {
280 let mut a = crate::p32::ONE;
281 let mut b = crate::p32::MINUS_ONE;
282 let _ = a - b;
283 let _ = &a - b;
284 let _ = a - &b;
285 let _ = &a - &b;
286 a -= b;
287 b -= &a;
288 }
289
290 fn is_correct_rounded<const N: u32, const ES: u32, Int: crate::Int>(
292 a: Posit<N, ES, Int>,
293 b: Posit<N, ES, Int>,
294 ) -> bool
295 where
296 Rational: TryFrom<Posit<N, ES, Int>>,
297 <Rational as TryFrom<Posit<N, ES, Int>>>::Error: core::fmt::Debug
298 {
299 let sub_posit = a - b;
300 if let (Ok(a), Ok(b)) = (Rational::try_from(a), Rational::try_from(b)) {
301 let sub_exact = a - b;
302 super::rational::is_correct_rounded(sub_exact, sub_posit)
303 } else {
304 sub_posit == Posit::<N, ES, Int>::NAR
305 }
306 }
307
308 #[test]
309 fn posit_10_0_exhaustive() {
310 for a in Posit::<10, 0, i16>::cases_exhaustive_all() {
311 for b in Posit::<10, 0, i16>::cases_exhaustive_all() {
312 assert!(is_correct_rounded(a, b), "{:?}: {:?}", a, b)
313 }
314 }
315 }
316
317 #[test]
318 fn posit_10_1_exhaustive() {
319 for a in Posit::<10, 1, i16>::cases_exhaustive_all() {
320 for b in Posit::<10, 1, i16>::cases_exhaustive_all() {
321 assert!(is_correct_rounded(a, b), "{:?}: {:?}", a, b)
322 }
323 }
324 }
325
326 #[test]
327 fn posit_10_2_exhaustive() {
328 for a in Posit::<10, 2, i16>::cases_exhaustive_all() {
329 for b in Posit::<10, 2, i16>::cases_exhaustive_all() {
330 assert!(is_correct_rounded(a, b), "{:?}: {:?}", a, b)
331 }
332 }
333 }
334
335 #[test]
336 fn posit_10_3_exhaustive() {
337 for a in Posit::<10, 3, i16>::cases_exhaustive_all() {
338 for b in Posit::<10, 3, i16>::cases_exhaustive_all() {
339 assert!(is_correct_rounded(a, b), "{:?}: {:?}", a, b)
340 }
341 }
342 }
343
344 #[test]
345 fn posit_8_0_exhaustive() {
346 for a in Posit::<8, 0, i8>::cases_exhaustive_all() {
347 for b in Posit::<8, 0, i8>::cases_exhaustive_all() {
348 assert!(is_correct_rounded(a, b), "{:?}: {:?}", a, b)
349 }
350 }
351 }
352
353 #[test]
354 fn p8_exhaustive() {
355 for a in crate::p8::cases_exhaustive_all() {
356 for b in crate::p8::cases_exhaustive_all() {
357 assert!(is_correct_rounded(a, b), "{:?}: {:?}", a, b)
358 }
359 }
360 }
361
362 use proptest::prelude::*;
363 const PROPTEST_CASES: u32 = if cfg!(debug_assertions) {0x1_0000} else {0x80_0000};
364 proptest!{
365 #![proptest_config(ProptestConfig::with_cases(PROPTEST_CASES))]
366
367 #[test]
368 fn p16_proptest(
369 a in crate::p16::cases_proptest(),
370 b in crate::p16::cases_proptest(),
371 ) {
372 assert!(is_correct_rounded(a, b), "{:?}: {:?}", a, b)
373 }
374
375 #[test]
376 fn p32_proptest(
377 a in crate::p32::cases_proptest(),
378 b in crate::p32::cases_proptest(),
379 ) {
380 assert!(is_correct_rounded(a, b), "{:?}: {:?}", a, b)
381 }
382
383 #[test]
384 fn p64_proptest(
385 a in crate::p64::cases_proptest(),
386 b in crate::p64::cases_proptest(),
387 ) {
388 assert!(is_correct_rounded(a, b), "{:?}: {:?}", a, b)
389 }
390 }
391
392 #[test]
393 fn posit_3_0_exhaustive() {
394 for a in Posit::<3, 0, i8>::cases_exhaustive_all() {
395 for b in Posit::<3, 0, i8>::cases_exhaustive_all() {
396 assert!(is_correct_rounded(a, b), "{:?}: {:?}", a, b)
397 }
398 }
399 }
400 #[test]
401 fn posit_4_0_exhaustive() {
402 for a in Posit::<4, 0, i8>::cases_exhaustive_all() {
403 for b in Posit::<4, 0, i8>::cases_exhaustive_all() {
404 assert!(is_correct_rounded(a, b), "{:?}: {:?}", a, b)
405 }
406 }
407 }
408 #[test]
409 fn posit_4_1_exhaustive() {
410 for a in Posit::<4, 1, i8>::cases_exhaustive_all() {
411 for b in Posit::<4, 1, i8>::cases_exhaustive_all() {
412 assert!(is_correct_rounded(a, b), "{:?}: {:?}", a, b)
413 }
414 }
415 }
416 }
417}