| use compiler_builtins::int::{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{:016x}{:016x}{:016x}{:016x}", |
| v.0[3], v.0[2], v.0[1], v.0[0] |
| ) |
| } |
| |
| #[test] |
| fn widen_u128() { |
| assert_eq!(u128::MAX.widen(), u256([u64::MAX, u64::MAX, 0, 0])); |
| assert_eq!( |
| LOHI_SPLIT.widen(), |
| u256([u64::MAX, 0xaaaaaaaaaaaaaaaa, 0, 0]) |
| ); |
| } |
| |
| #[test] |
| fn widen_i128() { |
| assert_eq!((-1i128).widen(), u256::MAX.signed()); |
| assert_eq!( |
| (LOHI_SPLIT as i128).widen(), |
| i256([u64::MAX, 0xaaaaaaaaaaaaaaaa, u64::MAX, u64::MAX]) |
| ); |
| assert_eq!((-1i128).zero_widen().unsigned(), (u128::MAX).widen()); |
| } |
| |
| #[test] |
| fn widen_mul_u128() { |
| let tests = [ |
| (u128::MAX / 2, 2_u128, u256([u64::MAX - 1, u64::MAX, 0, 0])), |
| (u128::MAX, 2_u128, u256([u64::MAX - 1, u64::MAX, 1, 0])), |
| (u128::MAX, u128::MAX, u256([1, 0, u64::MAX - 1, u64::MAX])), |
| (u128::MIN, u128::MIN, u256::ZERO), |
| (1234, 0, u256::ZERO), |
| (0, 1234, u256::ZERO), |
| ]; |
| |
| let mut errors = Vec::new(); |
| 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 { |
| errors.push((i, a, b, exp, res)); |
| } |
| } |
| |
| for (i, a, b, exp, res) in &errors { |
| eprintln!( |
| "FAILURE ({i}): {a:#034x} * {b:#034x} = {} got {}", |
| hexu(*exp), |
| hexu(*res) |
| ); |
| } |
| assert!(errors.is_empty()); |
| } |
| |
| #[test] |
| fn not_u128() { |
| assert_eq!(!u256::ZERO, u256::MAX); |
| } |
| |
| #[test] |
| fn shr_u128() { |
| let only_low = [ |
| 1, |
| u16::MAX.into(), |
| u32::MAX.into(), |
| u64::MAX.into(), |
| u128::MAX, |
| ]; |
| |
| let mut errors = Vec::new(); |
| |
| 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 { |
| errors.push((a.widen(), shift, res, expected)); |
| } |
| } |
| } |
| } |
| |
| let check = [ |
| ( |
| u256::MAX, |
| 1, |
| u256([u64::MAX, u64::MAX, u64::MAX, u64::MAX >> 1]), |
| ), |
| ( |
| u256::MAX, |
| 5, |
| u256([u64::MAX, u64::MAX, u64::MAX, u64::MAX >> 5]), |
| ), |
| (u256::MAX, 63, u256([u64::MAX, u64::MAX, u64::MAX, 1])), |
| (u256::MAX, 64, u256([u64::MAX, u64::MAX, u64::MAX, 0])), |
| (u256::MAX, 65, u256([u64::MAX, u64::MAX, u64::MAX >> 1, 0])), |
| (u256::MAX, 127, u256([u64::MAX, u64::MAX, 1, 0])), |
| (u256::MAX, 128, u256([u64::MAX, u64::MAX, 0, 0])), |
| (u256::MAX, 129, u256([u64::MAX, u64::MAX >> 1, 0, 0])), |
| (u256::MAX, 191, u256([u64::MAX, 1, 0, 0])), |
| (u256::MAX, 192, u256([u64::MAX, 0, 0, 0])), |
| (u256::MAX, 193, u256([u64::MAX >> 1, 0, 0, 0])), |
| (u256::MAX, 191, u256([u64::MAX, 1, 0, 0])), |
| (u256::MAX, 254, u256([0b11, 0, 0, 0])), |
| (u256::MAX, 255, u256([1, 0, 0, 0])), |
| ]; |
| |
| for (input, shift, expected) in check { |
| let res = input >> shift; |
| if res != expected { |
| errors.push((input, shift, res, expected)); |
| } |
| } |
| |
| for (a, b, res, expected) in &errors { |
| eprintln!( |
| "FAILURE: {} >> {b} = {} got {}", |
| hexu(*a), |
| hexu(*expected), |
| hexu(*res), |
| ); |
| } |
| assert!(errors.is_empty()); |
| } |