| 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; |
| } |
| } |