Skip to content

Commit 7809cef

Browse files
committed
Implement wrapping and overflowing traits
Add wrapping and overflowing add/sub for completeness. These are otherwise equivalent to checked() versions, except in unsigned subtraction wrapping around zero.
1 parent a25836e commit 7809cef

File tree

6 files changed

+243
-0
lines changed

6 files changed

+243
-0
lines changed

src/bigint/addition.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ use core::iter::Sum;
99
use core::mem;
1010
use core::ops::{Add, AddAssign};
1111
use num_traits::CheckedAdd;
12+
use num_traits::WrappingAdd;
13+
use num_traits::ops::overflowing::OverflowingAdd;
1214

1315
// We want to forward to BigUint::add, but it's not clear how that will go until
1416
// we compare both sign and magnitude. So we duplicate this body for every
@@ -236,4 +238,20 @@ impl CheckedAdd for BigInt {
236238
}
237239
}
238240

241+
// Never wraps, unless we are out of memory
242+
impl WrappingAdd for BigInt {
243+
#[inline]
244+
fn wrapping_add(&self, v: &BigInt) -> BigInt {
245+
self.add(v)
246+
}
247+
}
248+
249+
// Overflow never occurs, unless we are out of memory
250+
impl OverflowingAdd for BigInt {
251+
#[inline]
252+
fn overflowing_add(&self, v: &BigInt) -> (BigInt, bool) {
253+
(self.add(v), false)
254+
}
255+
}
256+
239257
impl_sum_iter_type!(BigInt);

src/bigint/subtraction.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ use core::cmp::Ordering::{Equal, Greater, Less};
88
use core::mem;
99
use core::ops::{Sub, SubAssign};
1010
use num_traits::CheckedSub;
11+
use num_traits::WrappingSub;
12+
use num_traits::ops::overflowing::OverflowingSub;
1113

1214
// We want to forward to BigUint::sub, but it's not clear how that will go until
1315
// we compare both sign and magnitude. So we duplicate this body for every
@@ -298,3 +300,19 @@ impl CheckedSub for BigInt {
298300
Some(self.sub(v))
299301
}
300302
}
303+
304+
// Never wraps, unless we are out of memory
305+
impl WrappingSub for BigInt {
306+
#[inline]
307+
fn wrapping_sub(&self, v: &BigInt) -> BigInt {
308+
self.sub(v)
309+
}
310+
}
311+
312+
// Overflow never occurs, unless we are out of memory
313+
impl OverflowingSub for BigInt {
314+
#[inline]
315+
fn overflowing_sub(&self, v: &BigInt) -> (BigInt, bool) {
316+
(self.sub(v), false)
317+
}
318+
}

src/biguint/addition.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use crate::UsizePromotion;
66
use core::iter::Sum;
77
use core::ops::{Add, AddAssign};
88
use num_traits::CheckedAdd;
9+
use num_traits::WrappingAdd;
10+
use num_traits::ops::overflowing::OverflowingAdd;
911

1012
#[cfg(target_arch = "x86_64")]
1113
use core::arch::x86_64 as arch;
@@ -253,4 +255,20 @@ impl CheckedAdd for BigUint {
253255
}
254256
}
255257

258+
// Never wraps, unless we are out of memory
259+
impl WrappingAdd for BigUint {
260+
#[inline]
261+
fn wrapping_add(&self, v: &BigUint) -> BigUint {
262+
self.add(v)
263+
}
264+
}
265+
266+
// Never overflows, unless we are out of memory
267+
impl OverflowingAdd for BigUint {
268+
#[inline]
269+
fn overflowing_add(&self, v: &BigUint) -> (BigUint, bool) {
270+
(self.add(v), false)
271+
}
272+
}
273+
256274
impl_sum_iter_type!(BigUint);

src/biguint/subtraction.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use crate::UsizePromotion;
66
use core::cmp::Ordering::{Equal, Greater, Less};
77
use core::ops::{Sub, SubAssign};
88
use num_traits::CheckedSub;
9+
use num_traits::WrappingSub;
10+
use num_traits::ops::overflowing::OverflowingSub;
911

1012
#[cfg(target_arch = "x86_64")]
1113
use core::arch::x86_64 as arch;
@@ -310,3 +312,25 @@ impl CheckedSub for BigUint {
310312
}
311313
}
312314
}
315+
316+
// This would wrap if second argument is greater than first argument
317+
// However, the result would be infinite, so we panic
318+
impl WrappingSub for BigUint {
319+
#[inline]
320+
fn wrapping_sub(&self, v: &BigUint) -> BigUint {
321+
assert!(self >= v, "Wrap would yield an infinite result");
322+
self.sub(v)
323+
}
324+
}
325+
326+
// This would overflow if second argument is greater than first argument
327+
// However, the result would be infinite, so we panic
328+
// Note that overflow=true cannot be returned, as we cannot return a
329+
// correct wrapped result.
330+
impl OverflowingSub for BigUint {
331+
#[inline]
332+
fn overflowing_sub(&self, v: &BigUint) -> (BigUint, bool) {
333+
assert!(self >= v, "Overflow would yield an infinite result");
334+
(self.sub(v), false)
335+
}
336+
}

tests/bigint.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ use num_integer::Integer;
1313
use num_traits::{
1414
pow, Euclid, FromBytes, FromPrimitive, Num, One, Pow, Signed, ToBytes, ToPrimitive, Zero,
1515
};
16+
use num_traits::ops::wrapping::WrappingAdd;
17+
use num_traits::ops::overflowing::OverflowingAdd;
18+
use num_traits::ops::wrapping::WrappingSub;
19+
use num_traits::ops::overflowing::OverflowingSub;
1620

1721
mod consts;
1822
use crate::consts::*;
@@ -978,6 +982,43 @@ fn test_checked_add() {
978982
}
979983
}
980984

985+
#[test]
986+
fn test_wrapping_add() {
987+
for elm in SUM_TRIPLES.iter() {
988+
let (a_vec, b_vec, c_vec) = *elm;
989+
let a = BigInt::from_slice(Plus, a_vec);
990+
let b = BigInt::from_slice(Plus, b_vec);
991+
let c = BigInt::from_slice(Plus, c_vec);
992+
993+
assert_eq!(a.wrapping_add(&b), c);
994+
assert_eq!(b.wrapping_add(&a), c);
995+
assert_eq!(c.wrapping_add(&(-&a)), b);
996+
assert_eq!(c.wrapping_add(&(-&b)), a);
997+
assert_eq!(a.wrapping_add(&(-&c)), (-&b));
998+
assert_eq!(b.wrapping_add(&(-&c)), (-&a));
999+
assert_eq!((-&a).wrapping_add(&(-&b)), (-&c));
1000+
assert_eq!(a.wrapping_add(&(-&a)), BigInt::zero());
1001+
}
1002+
}
1003+
1004+
#[test]
1005+
fn test_overflowing_add() {
1006+
for elm in SUM_TRIPLES.iter() {
1007+
let (a_vec, b_vec, c_vec) = *elm;
1008+
let a = BigInt::from_slice(Plus, a_vec);
1009+
let b = BigInt::from_slice(Plus, b_vec);
1010+
let c = BigInt::from_slice(Plus, c_vec);
1011+
1012+
assert_eq!(a.overflowing_add(&b), (c.clone(), false));
1013+
assert_eq!(b.overflowing_add(&a), (c.clone(), false));
1014+
assert_eq!(c.overflowing_add(&(-&a)), (b.clone(), false));
1015+
assert_eq!(c.overflowing_add(&(-&b)), (a.clone(), false));
1016+
assert_eq!(a.overflowing_add(&(-&c)), ((-&b).clone(), false));
1017+
assert_eq!(b.overflowing_add(&(-&c)), ((-&a).clone(), false));
1018+
assert_eq!(c.overflowing_add(&(-&c)), (BigInt::zero(), false));
1019+
}
1020+
}
1021+
9811022
#[test]
9821023
fn test_checked_sub() {
9831024
for elm in SUM_TRIPLES.iter() {
@@ -997,6 +1038,44 @@ fn test_checked_sub() {
9971038
}
9981039
}
9991040

1041+
#[test]
1042+
fn test_wrapping_sub() {
1043+
for elm in SUM_TRIPLES.iter() {
1044+
let (a_vec, b_vec, c_vec) = *elm;
1045+
let a = BigInt::from_slice(Plus, a_vec);
1046+
let b = BigInt::from_slice(Plus, b_vec);
1047+
let c = BigInt::from_slice(Plus, c_vec);
1048+
1049+
assert_eq!(c.wrapping_sub(&a), b);
1050+
assert_eq!(c.wrapping_sub(&b), a);
1051+
assert_eq!((-&b).wrapping_sub(&a), (-&c));
1052+
assert_eq!((-&a).wrapping_sub(&b), (-&c));
1053+
assert_eq!(b.wrapping_sub(&(-&a)), c);
1054+
assert_eq!(a.wrapping_sub(&(-&b)), c);
1055+
assert_eq!((-&c).wrapping_sub(&(-&a)), (-&b));
1056+
assert_eq!(a.wrapping_sub(&a), BigInt::zero());
1057+
}
1058+
}
1059+
1060+
#[test]
1061+
fn test_overflowing_sub() {
1062+
for elm in SUM_TRIPLES.iter() {
1063+
let (a_vec, b_vec, c_vec) = *elm;
1064+
let a = BigInt::from_slice(Plus, a_vec);
1065+
let b = BigInt::from_slice(Plus, b_vec);
1066+
let c = BigInt::from_slice(Plus, c_vec);
1067+
1068+
assert_eq!(c.overflowing_sub(&a), (b.clone(), false));
1069+
assert_eq!(c.overflowing_sub(&b), (a.clone(), false));
1070+
assert_eq!((-&b).overflowing_sub(&a), ((-&c).clone(), false));
1071+
assert_eq!((-&a).overflowing_sub(&b), ((-&c).clone(), false));
1072+
assert_eq!(b.overflowing_sub(&(-&a)), (c.clone(), false));
1073+
assert_eq!(a.overflowing_sub(&(-&b)), (c.clone(), false));
1074+
assert_eq!((-&c).overflowing_sub(&(-&a)), ((-&b).clone(), false));
1075+
assert_eq!(a.overflowing_sub(&a), (BigInt::zero(), false));
1076+
}
1077+
}
1078+
10001079
#[test]
10011080
fn test_checked_mul() {
10021081
for elm in MUL_TRIPLES.iter() {

tests/biguint.rs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ use num_traits::{
1414
pow, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Euclid, FromBytes, FromPrimitive, Num,
1515
One, Pow, ToBytes, ToPrimitive, Zero,
1616
};
17+
use num_traits::WrappingAdd;
18+
use num_traits::ops::overflowing::OverflowingAdd;
19+
use num_traits::WrappingSub;
20+
use num_traits::ops::overflowing::OverflowingSub;
1721

1822
mod consts;
1923
use crate::consts::*;
@@ -1006,6 +1010,33 @@ fn test_checked_add() {
10061010
}
10071011
}
10081012

1013+
#[test]
1014+
fn test_wrapping_add() {
1015+
for elm in SUM_TRIPLES.iter() {
1016+
let (a_vec, b_vec, c_vec) = *elm;
1017+
let a = BigUint::from_slice(a_vec);
1018+
let b = BigUint::from_slice(b_vec);
1019+
let c = BigUint::from_slice(c_vec);
1020+
1021+
assert_eq!(a.wrapping_add(&b), c);
1022+
assert_eq!(b.wrapping_add(&a), c);
1023+
}
1024+
}
1025+
1026+
#[test]
1027+
fn test_overflowing_add() {
1028+
for elm in SUM_TRIPLES.iter() {
1029+
let (a_vec, b_vec, c_vec) = *elm;
1030+
let a = BigUint::from_slice(a_vec);
1031+
let b = BigUint::from_slice(b_vec);
1032+
let c = BigUint::from_slice(c_vec);
1033+
let c_1 = BigUint::from_slice(c_vec);
1034+
1035+
assert_eq!(a.overflowing_add(&b), (c, false));
1036+
assert_eq!(b.overflowing_add(&a), (c_1, false));
1037+
}
1038+
}
1039+
10091040
#[test]
10101041
fn test_checked_sub() {
10111042
for elm in SUM_TRIPLES.iter() {
@@ -1026,6 +1057,61 @@ fn test_checked_sub() {
10261057
}
10271058
}
10281059

1060+
#[test]
1061+
fn test_wrapping_sub() {
1062+
for elm in SUM_TRIPLES.iter() {
1063+
let (a_vec, b_vec, c_vec) = *elm;
1064+
let a = BigUint::from_slice(a_vec);
1065+
let b = BigUint::from_slice(b_vec);
1066+
let c = BigUint::from_slice(c_vec);
1067+
1068+
assert_eq!(c.wrapping_sub(&a), b);
1069+
assert_eq!(c.wrapping_sub(&b), a);
1070+
if a >= c {
1071+
assert_eq!(a.wrapping_sub(&c), b);
1072+
}
1073+
if b >= c {
1074+
assert_eq!(b.wrapping_sub(&c), a);
1075+
}
1076+
}
1077+
}
1078+
1079+
#[test]
1080+
#[should_panic]
1081+
fn test_wrapping_sub_should_panic() {
1082+
let a = BigUint::from(100u32);
1083+
let b = BigUint::from(200u32);
1084+
let _ = a.wrapping_sub(&b);
1085+
}
1086+
1087+
#[test]
1088+
fn test_overflowing_sub() {
1089+
for elm in SUM_TRIPLES.iter() {
1090+
let (a_vec, b_vec, c_vec) = *elm;
1091+
let a = BigUint::from_slice(a_vec);
1092+
let b = BigUint::from_slice(b_vec);
1093+
let c = BigUint::from_slice(c_vec);
1094+
1095+
assert_eq!(c.overflowing_sub(&a), (b.clone(), false));
1096+
assert_eq!(c.overflowing_sub(&b), (a.clone(), false));
1097+
1098+
if a >= c {
1099+
assert_eq!(a.overflowing_sub(&c), (b.clone(), false));
1100+
}
1101+
if b >= c {
1102+
assert_eq!(b.overflowing_sub(&c), (a.clone(), false));
1103+
}
1104+
}
1105+
}
1106+
1107+
#[test]
1108+
#[should_panic]
1109+
fn test_overflowing_sub_should_panic() {
1110+
let a = BigUint::from(100u32);
1111+
let b = BigUint::from(200u32);
1112+
let _ = a.overflowing_sub(&b);
1113+
}
1114+
10291115
#[test]
10301116
fn test_checked_mul() {
10311117
for elm in MUL_TRIPLES.iter() {

0 commit comments

Comments
 (0)