Skip to content

Commit ff52c97

Browse files
committed
better support for u256 and i256
1 parent 674910e commit ff52c97

File tree

4 files changed

+98
-35
lines changed

4 files changed

+98
-35
lines changed

libm-test/tests/u256.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,13 @@ fn mp_u256_add() {
111111
let y = random_u256(&mut rng);
112112
assign_bigint(&mut bx, x);
113113
assign_bigint(&mut by, y);
114-
let actual = x + y;
114+
let actual = if u256::MAX - x >= y {
115+
x + y
116+
} else {
117+
// otherwise (u256::MAX - x) < y, so the wrapped result is
118+
// (x + y) - (u256::MAX + 1) == y - (u256::MAX - x) - 1
119+
y - (u256::MAX - x) - 1_u128.widen()
120+
};
115121
bx += &by;
116122
check_one(|| hexu(x), || Some(hexu(y)), actual, &mut bx);
117123
}

libm/src/math/support/big.rs

Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ const U128_LO_MASK: u128 = u64::MAX as u128;
1111

1212
/// A 256-bit unsigned integer represented as two 128-bit native-endian limbs.
1313
#[allow(non_camel_case_types)]
14-
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
14+
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord)]
1515
pub struct u256 {
16-
pub lo: u128,
1716
pub hi: u128,
17+
pub lo: u128,
1818
}
1919

2020
impl u256 {
@@ -28,17 +28,17 @@ impl u256 {
2828
pub fn signed(self) -> i256 {
2929
i256 {
3030
lo: self.lo,
31-
hi: self.hi,
31+
hi: self.hi as i128,
3232
}
3333
}
3434
}
3535

3636
/// A 256-bit signed integer represented as two 128-bit native-endian limbs.
3737
#[allow(non_camel_case_types)]
38-
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
38+
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord)]
3939
pub struct i256 {
40+
pub hi: i128,
4041
pub lo: u128,
41-
pub hi: u128,
4242
}
4343

4444
impl i256 {
@@ -47,7 +47,7 @@ impl i256 {
4747
pub fn unsigned(self) -> u256 {
4848
u256 {
4949
lo: self.lo,
50-
hi: self.hi,
50+
hi: self.hi as u128,
5151
}
5252
}
5353
}
@@ -73,17 +73,17 @@ impl MinInt for i256 {
7373

7474
type Unsigned = u256;
7575

76-
const SIGNED: bool = false;
76+
const SIGNED: bool = true;
7777
const BITS: u32 = 256;
7878
const ZERO: Self = Self { lo: 0, hi: 0 };
7979
const ONE: Self = Self { lo: 1, hi: 0 };
8080
const MIN: Self = Self {
81-
lo: 0,
82-
hi: 1 << 127,
81+
lo: u128::MIN,
82+
hi: i128::MIN,
8383
};
8484
const MAX: Self = Self {
8585
lo: u128::MAX,
86-
hi: u128::MAX >> 1,
86+
hi: i128::MAX,
8787
};
8888
}
8989

@@ -116,23 +116,44 @@ macro_rules! impl_common {
116116
unimplemented!("only used to meet trait bounds")
117117
}
118118
}
119-
};
120-
}
121119

122-
impl_common!(i256);
123-
impl_common!(u256);
120+
impl ops::Add<Self> for $ty {
121+
type Output = Self;
124122

125-
impl ops::Add<Self> for u256 {
126-
type Output = Self;
123+
fn add(self, rhs: Self) -> Self::Output {
124+
let (lo, carry) = self.lo.overflowing_add(rhs.lo);
125+
let (hi, of) = Int::carrying_add(self.hi, rhs.hi, carry);
127126

128-
fn add(self, rhs: Self) -> Self::Output {
129-
let (lo, carry) = self.lo.overflowing_add(rhs.lo);
130-
let hi = self.hi.wrapping_add(carry as u128).wrapping_add(rhs.hi);
127+
#[cfg(debug_assertions)]
128+
if of {
129+
panic!("attempt to add with overflow")
130+
}
131131

132-
Self { lo, hi }
133-
}
132+
Self { lo, hi }
133+
}
134+
}
135+
136+
impl ops::Sub<Self> for $ty {
137+
type Output = Self;
138+
139+
fn sub(self, rhs: Self) -> Self::Output {
140+
let (lo, borrow) = self.lo.overflowing_sub(rhs.lo);
141+
let (hi, of) = Int::borrowing_sub(self.hi, rhs.hi, borrow);
142+
143+
#[cfg(debug_assertions)]
144+
if of {
145+
panic!("attempt to subtract with overflow")
146+
}
147+
148+
Self { lo, hi }
149+
}
150+
}
151+
};
134152
}
135153

154+
impl_common!(i256);
155+
impl_common!(u256);
156+
136157
impl ops::Shr<u32> for u256 {
137158
type Output = Self;
138159

@@ -200,19 +221,18 @@ impl HInt for u128 {
200221
}
201222

202223
fn widen_hi(self) -> Self::D {
203-
self.widen() << <Self as MinInt>::BITS
224+
u256 { lo: 0, hi: self }
204225
}
205226
}
206227

207228
impl HInt for i128 {
208229
type D = i256;
209230

210231
fn widen(self) -> Self::D {
211-
let mut ret = self.unsigned().zero_widen().signed();
212-
if self.is_negative() {
213-
ret.hi = u128::MAX;
232+
i256 {
233+
lo: self as u128,
234+
hi: if self < 0 { -1 } else { 0 },
214235
}
215-
ret
216236
}
217237

218238
fn zero_widen(self) -> Self::D {
@@ -228,7 +248,7 @@ impl HInt for i128 {
228248
}
229249

230250
fn widen_hi(self) -> Self::D {
231-
self.widen() << <Self as MinInt>::BITS
251+
i256 { lo: 0, hi: self }
232252
}
233253
}
234254

@@ -252,6 +272,6 @@ impl DInt for i256 {
252272
}
253273

254274
fn hi(self) -> Self::H {
255-
self.hi as i128
275+
self.hi
256276
}
257277
}

libm/src/math/support/big/tests.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ fn widen_i128() {
3636
(LOHI_SPLIT as i128).widen(),
3737
i256 {
3838
lo: LOHI_SPLIT,
39-
hi: u128::MAX
39+
hi: -1,
4040
}
4141
);
4242
assert_eq!((-1i128).zero_widen().unsigned(), (u128::MAX).widen());
@@ -275,3 +275,26 @@ fn shr_u256_overflow() {
275275
assert_eq!(u256::MAX >> 257, u256::ZERO);
276276
assert_eq!(u256::MAX >> u32::MAX, u256::ZERO);
277277
}
278+
279+
#[test]
280+
fn u256_ord() {
281+
let _1 = u256::ONE;
282+
let _2 = _1 + _1;
283+
for x in u8::MIN..u8::MAX {
284+
let y = x + 1;
285+
let wx = (x as u128).widen_hi();
286+
let wy = (y as u128).widen_hi();
287+
assert!([wx, wx + _1, wx + _2, wy, wy + _1, wy + _2].is_sorted());
288+
}
289+
}
290+
#[test]
291+
fn i256_ord() {
292+
let _1 = i256::ONE;
293+
let _2 = _1 + _1;
294+
for x in i8::MIN..i8::MAX {
295+
let y = x + 1;
296+
let wx = (x as i128).widen_hi();
297+
let wy = (y as i128).widen_hi();
298+
assert!([wx, wx + _1, wx + _2, wy - _2, wy - _1, wy].is_sorted());
299+
}
300+
}

libm/src/math/support/int_traits.rs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ use core::{cmp, fmt, ops};
55
pub trait MinInt:
66
Copy
77
+ fmt::Debug
8+
+ cmp::Ord
89
+ ops::BitOr<Output = Self>
910
+ ops::Not<Output = Self>
1011
+ ops::Shl<u32, Output = Self>
12+
+ ops::Add<Output = Self>
13+
+ ops::Sub<Output = Self>
1114
{
1215
/// Type with the same width but other signedness
1316
type OtherSign: MinInt;
@@ -37,8 +40,6 @@ pub trait Int:
3740
+ fmt::Display
3841
+ fmt::Binary
3942
+ fmt::LowerHex
40-
+ PartialEq
41-
+ PartialOrd
4243
+ ops::AddAssign
4344
+ ops::SubAssign
4445
+ ops::MulAssign
@@ -51,8 +52,6 @@ pub trait Int:
5152
+ ops::ShlAssign<u32>
5253
+ ops::ShrAssign<u32>
5354
+ ops::ShrAssign<i32>
54-
+ ops::Add<Output = Self>
55-
+ ops::Sub<Output = Self>
5655
+ ops::Mul<Output = Self>
5756
+ ops::Div<Output = Self>
5857
+ ops::Rem<Output = Self>
@@ -62,7 +61,6 @@ pub trait Int:
6261
+ ops::Shr<u32, Output = Self>
6362
+ ops::BitXor<Output = Self>
6463
+ ops::BitAnd<Output = Self>
65-
+ cmp::Ord
6664
+ From<bool>
6765
+ CastFrom<i32>
6866
+ CastFrom<u16>
@@ -102,6 +100,8 @@ pub trait Int:
102100
fn rotate_left(self, other: u32) -> Self;
103101
fn overflowing_add(self, other: Self) -> (Self, bool);
104102
fn overflowing_sub(self, other: Self) -> (Self, bool);
103+
fn carrying_add(self, other: Self, carry: bool) -> (Self, bool);
104+
fn borrowing_sub(self, other: Self, borrow: bool) -> (Self, bool);
105105
fn leading_zeros(self) -> u32;
106106
fn ilog2(self) -> u32;
107107
}
@@ -174,6 +174,20 @@ macro_rules! int_impl_common {
174174
#[allow(clippy::incompatible_msrv)]
175175
<Self>::ilog2(self)
176176
}
177+
178+
fn carrying_add(self, other: Self, carry: bool) -> (Self, bool) {
179+
let (ab, of1) = self.overflowing_add(other);
180+
let (abc, of2) = ab.overflowing_add(Self::from_bool(carry));
181+
// `of1 && of2` is possible with signed integers if a negative sum
182+
// overflows to `MAX` and adding the carry overflows again back to `MIN`
183+
(abc, of1 ^ of2)
184+
}
185+
186+
fn borrowing_sub(self, other: Self, borrow: bool) -> (Self, bool) {
187+
let (ab, of1) = self.overflowing_sub(other);
188+
let (abc, of2) = ab.overflowing_sub(Self::from_bool(borrow));
189+
(abc, of1 ^ of2)
190+
}
177191
};
178192
}
179193

0 commit comments

Comments
 (0)