blob: d54706c726072d8374ac0f4f8d71d557bd97aa36 [file] [log] [blame]
extern crate std;
use std::string::String;
use std::{eprintln, format};
use super::{HInt, MinInt, i256, u256};
const LOHI_SPLIT: u128 = 0xaaaaaaaaaaaaaaaaffffffffffffffff;
/// Print a `u256` as hex since we can't add format implementations
fn hexu(v: u256) -> String {
format!("0x{:032x}{:032x}", v.hi, v.lo)
}
#[test]
fn widen_u128() {
assert_eq!(
u128::MAX.widen(),
u256 {
lo: u128::MAX,
hi: 0
}
);
assert_eq!(
LOHI_SPLIT.widen(),
u256 {
lo: LOHI_SPLIT,
hi: 0
}
);
}
#[test]
fn widen_i128() {
assert_eq!((-1i128).widen(), u256::MAX.signed());
assert_eq!(
(LOHI_SPLIT as i128).widen(),
i256 {
lo: LOHI_SPLIT,
hi: -1,
}
);
assert_eq!((-1i128).zero_widen().unsigned(), (u128::MAX).widen());
}
#[test]
fn widen_mul_u128() {
let tests = [
(
u128::MAX / 2,
2_u128,
u256 {
lo: u128::MAX - 1,
hi: 0,
},
),
(
u128::MAX,
2_u128,
u256 {
lo: u128::MAX - 1,
hi: 1,
},
),
(
u128::MAX,
u128::MAX,
u256 {
lo: 1,
hi: u128::MAX - 1,
},
),
(0, 0, u256::ZERO),
(1234u128, 0, u256::ZERO),
(0, 1234, u256::ZERO),
];
let mut has_errors = false;
let mut add_error = |i, a, b, expected, actual| {
has_errors = true;
eprintln!(
"\
FAILURE ({i}): {a:#034x} * {b:#034x}\n\
expected: {}\n\
got: {}\
",
hexu(expected),
hexu(actual)
);
};
for (i, (a, b, exp)) in tests.iter().copied().enumerate() {
let res = a.widen_mul(b);
let res_z = a.zero_widen_mul(b);
assert_eq!(res, res_z);
if res != exp {
add_error(i, a, b, exp, res);
}
}
assert!(!has_errors);
}
#[test]
fn not_u256() {
assert_eq!(!u256::ZERO, u256::MAX);
}
#[test]
fn shr_u256() {
let only_low = [
1,
u16::MAX.into(),
u32::MAX.into(),
u64::MAX.into(),
u128::MAX,
];
let mut has_errors = false;
let mut add_error = |a, b, expected, actual| {
has_errors = true;
eprintln!(
"\
FAILURE: {} >> {b}\n\
expected: {}\n\
actual: {}\
",
hexu(a),
hexu(expected),
hexu(actual),
);
};
for a in only_low {
for perturb in 0..10 {
let a = a.saturating_add(perturb);
for shift in 0..128 {
let res = a.widen() >> shift;
let expected = (a >> shift).widen();
if res != expected {
add_error(a.widen(), shift, expected, res);
}
}
}
}
let check = [
(
u256::MAX,
1,
u256 {
lo: u128::MAX,
hi: u128::MAX >> 1,
},
),
(
u256::MAX,
5,
u256 {
lo: u128::MAX,
hi: u128::MAX >> 5,
},
),
(
u256::MAX,
63,
u256 {
lo: u128::MAX,
hi: u64::MAX as u128 | (1 << 64),
},
),
(
u256::MAX,
64,
u256 {
lo: u128::MAX,
hi: u64::MAX as u128,
},
),
(
u256::MAX,
65,
u256 {
lo: u128::MAX,
hi: (u64::MAX >> 1) as u128,
},
),
(
u256::MAX,
127,
u256 {
lo: u128::MAX,
hi: 1,
},
),
(
u256::MAX,
128,
u256 {
lo: u128::MAX,
hi: 0,
},
),
(
u256::MAX,
129,
u256 {
lo: u128::MAX >> 1,
hi: 0,
},
),
(
u256::MAX,
191,
u256 {
lo: u64::MAX as u128 | 1 << 64,
hi: 0,
},
),
(
u256::MAX,
192,
u256 {
lo: u64::MAX as u128,
hi: 0,
},
),
(
u256::MAX,
193,
u256 {
lo: u64::MAX as u128 >> 1,
hi: 0,
},
),
(u256::MAX, 254, u256 { lo: 0b11, hi: 0 }),
(u256::MAX, 255, u256 { lo: 1, hi: 0 }),
(
u256 {
hi: LOHI_SPLIT,
lo: 0,
},
64,
u256 {
lo: 0xffffffffffffffff0000000000000000,
hi: 0xaaaaaaaaaaaaaaaa,
},
),
];
for (input, shift, expected) in check {
let res = input >> shift;
if res != expected {
add_error(input, shift, expected, res);
}
}
assert!(!has_errors);
}
#[test]
#[should_panic]
#[cfg(debug_assertions)]
// FIXME(ppc): ppc64le seems to have issues with `should_panic` tests.
#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))]
fn shr_u256_overflow() {
// Like regular shr, panic on overflow with debug assertions
let _ = u256::MAX >> 256;
}
#[test]
#[cfg(not(debug_assertions))]
fn shr_u256_overflow() {
// No panic without debug assertions
assert_eq!(u256::MAX >> 256, u256::ZERO);
assert_eq!(u256::MAX >> 257, u256::ZERO);
assert_eq!(u256::MAX >> u32::MAX, u256::ZERO);
}
#[test]
fn u256_ord() {
let _1 = u256::ONE;
let _2 = _1 + _1;
for x in u8::MIN..u8::MAX {
let y = x + 1;
let wx = (x as u128).widen_hi();
let wy = (y as u128).widen_hi();
assert!([wx, wx + _1, wx + _2, wy, wy + _1, wy + _2].is_sorted());
}
}
#[test]
fn i256_ord() {
let _1 = i256::ONE;
let _2 = _1 + _1;
for x in i8::MIN..i8::MAX {
let y = x + 1;
let wx = (x as i128).widen_hi();
let wy = (y as i128).widen_hi();
assert!([wx, wx + _1, wx + _2, wy - _2, wy - _1, wy].is_sorted());
}
}
#[test]
fn u256_shifts() {
let _1 = u256::ONE;
for k in 0..255 {
let x = _1 << k;
let x2 = _1 << (k + 1);
assert!(x < x2);
assert_eq!(x << 1, x2);
assert_eq!(x + x, x2);
assert_eq!(x >> k, _1);
assert_eq!(x2 >> (k + 1), _1);
}
}
#[test]
fn i256_shifts() {
let _1 = i256::ONE;
for k in 0..254 {
let x = _1 << k;
let x2 = _1 << (k + 1);
assert!(x < x2);
assert_eq!(x << 1, x2);
assert_eq!(x + x, x2);
assert_eq!(x >> k, _1);
assert_eq!(x2 >> (k + 1), _1);
}
let min = _1 << 255;
assert_eq!(min, i256::MIN);
let mut x = min;
for k in 0..255 {
assert_eq!(x, min >> k);
let y = x >> 1;
assert_eq!(y + y, x);
assert!(x < y);
x = y;
}
}