use renew_fixed::{Fixed, Vec2, Vec3};
const ONE: i64 = 65536;
fn narrow_component_bound(dimension: i128) -> i128 {
let (mut lo, mut hi) = (0i128, i128::from(i64::MAX));
while lo < hi {
let mid = lo + (hi - lo).div_euclid(2) + 1;
let square = (mid * mid) >> 16;
if square * dimension <= i128::from(i64::MAX) {
lo = mid;
} else {
hi = mid - 1;
}
}
lo
}
#[test]
fn the_narrow_squared_length_bound_is_stated_for_the_right_operand() {
let two_d = narrow_component_bound(2);
let three_d = narrow_component_bound(3);
let one = i128::from(ONE);
assert_eq!(two_d / one, 8_388_607, "2D component bound, in units");
assert_eq!(three_d / one, 6_849_269, "3D component bound, in units");
assert_eq!(two_d / one / 2, 4_194_303, "2D coordinate bound, in units");
assert_eq!(
three_d / one / 2,
3_424_634,
"3D coordinate bound, in units"
);
let at = Fixed::from_bits(i64::try_from(two_d).unwrap_or(i64::MAX));
let past = Fixed::from_bits(i64::try_from(two_d + 1).unwrap_or(i64::MAX));
assert_eq!(
Vec2::new(at, at).length_squared_wide().checked_narrow(),
Some(Vec2::new(at, at).length_squared()),
"at the bound the two paths agree"
);
assert_ne!(
Vec2::new(past, past).length_squared_wide().checked_narrow(),
Some(Vec2::new(past, past).length_squared()),
"one raw unit past the bound the narrow path loses"
);
let between = Fixed::from_bits(i64::try_from(three_d + 1).unwrap_or(i64::MAX));
assert_ne!(
Vec3::new(between, between, between)
.length_squared_wide()
.checked_narrow(),
Some(Vec3::new(between, between, between).length_squared()),
"past the 3D bound the narrow path loses"
);
}
#[test]
fn a_wide_product_cannot_overflow_but_a_sum_of_them_can() {
let extreme = Fixed::MAX.wide_mul(Fixed::MAX);
assert!(extreme.to_bits() > 0, "a single wide product survives");
let before = renew_fixed::saturations();
let _ = extreme + extreme + extreme;
assert!(
renew_fixed::saturations().0 > before.0,
"three extreme products summed must report saturating"
);
}
#[test]
fn the_world_bound_differs_by_dimension_and_is_measured_at_the_bound() {
let largest_safe = |dimension: i128| {
let (mut lo, mut hi) = (0i128, i128::from(i64::MAX) / 2);
while lo < hi {
let mid = lo + (hi - lo).div_euclid(2) + 1;
let fits = (2 * mid)
.checked_mul(2 * mid)
.and_then(|square| square.checked_mul(dimension))
.is_some();
if fits {
lo = mid;
} else {
hi = mid - 1;
}
}
lo
};
let two_d = largest_safe(2);
let three_d = largest_safe(3);
let one = i128::from(ONE);
assert_eq!(
two_d,
i128::from(Fixed::MAX.to_bits() / 2),
"in 2D the subtraction bound and the wide bound are the same figure"
);
assert_eq!(two_d / one, 70_368_744_177_663, "2D world bound, in units");
assert_eq!(
three_d / one,
57_455_839_025_240,
"3D world bound, in units"
);
assert!(
three_d < two_d,
"the 3D bound must be the tighter one, or there is nothing to state"
);
let at = Fixed::from_bits(i64::try_from(three_d).unwrap_or(i64::MAX));
let past = Fixed::from_bits(i64::try_from(two_d).unwrap_or(i64::MAX));
let difference = |e: Fixed| e - Fixed::from_bits(-e.to_bits());
let before = renew_fixed::saturations();
let quiet = difference(at);
let _ = Vec3::new(quiet, quiet, quiet).length_squared_wide();
assert_eq!(
renew_fixed::saturations(),
before,
"at the 3D bound the mandated wide path must not saturate"
);
let loud = difference(past);
let _ = Vec3::new(loud, loud, loud).length_squared_wide();
assert!(
renew_fixed::saturations().0 > before.0,
"at the 2D figure a 3D distance must saturate — that is why the \
bound is stated per dimension"
);
let steady = renew_fixed::saturations();
let _ = Vec2::new(loud, loud).length_squared_wide();
assert_eq!(
renew_fixed::saturations(),
steady,
"the 2D bound must be quiet in 2D"
);
}
#[test]
fn the_slide_residual_scales_with_the_displacement() {
let permitted_divisor = ONE / (2 * 4);
assert_eq!(permitted_divisor, 8192, "permitted slope divisor");
for magnitude in [1i64, 10, 100, 1_000, 10_000] {
let permitted = 2 + (magnitude * ONE) / permitted_divisor;
let mut worst = 0i64;
for (dx, dy) in [(3i32, 4i32), (1, 1), (7, 2), (1, 100), (99, 1), (5, 12)] {
let normal = Vec2::new(Fixed::from_int(dx), Fixed::from_int(dy))
.normalize()
.expect("non-zero direction");
let push = Vec2::new(
Fixed::from_bits(normal.x.to_bits() * magnitude),
Fixed::from_bits(normal.y.to_bits() * magnitude),
);
let residual = push.slide_along(normal);
worst = worst.max(residual.x.to_bits().abs());
worst = worst.max(residual.y.to_bits().abs());
}
assert!(
worst <= permitted,
"at magnitude {magnitude} the residual was {worst}, past the permitted {permitted}"
);
let mut worst_3d = 0i64;
for (dx, dy, dz) in [
(1i32, 2i32, 2i32),
(2, 3, 6),
(1, 1, 1),
(7, 4, 4),
(1, 1, 100),
(99, 1, 1),
] {
let normal = Vec3::new(
Fixed::from_int(dx),
Fixed::from_int(dy),
Fixed::from_int(dz),
)
.normalize()
.expect("non-zero direction");
let push = Vec3::new(
Fixed::from_bits(normal.x.to_bits() * magnitude),
Fixed::from_bits(normal.y.to_bits() * magnitude),
Fixed::from_bits(normal.z.to_bits() * magnitude),
);
let residual = push.slide_along(normal);
worst_3d = worst_3d.max(residual.x.to_bits().abs());
worst_3d = worst_3d.max(residual.y.to_bits().abs());
worst_3d = worst_3d.max(residual.z.to_bits().abs());
}
assert!(
worst_3d <= permitted,
"at magnitude {magnitude} the 3D residual was {worst_3d}, past {permitted}"
);
}
}
#[test]
fn the_sixty_hertz_timestep_converts_with_a_stated_error() {
let nanos: i128 = 16_666_667;
let billion = 1_000_000_000i128;
let exact = nanos * i128::from(ONE);
let raw = (exact + billion / 2) / billion;
assert_eq!(raw, 1092, "60 Hz as a Q47.16 count of seconds");
let dt = Fixed::from_bits(i64::try_from(raw).unwrap_or(i64::MAX));
assert_eq!(dt.to_bits(), 1092);
let shortfall = exact - raw * billion;
assert_eq!(
shortfall * 1_000_000 / exact,
244,
"conversion error in parts per million"
);
let drift_raw = shortfall * 3600 * 10 / billion;
assert_eq!(
drift_raw * 1000 / i128::from(ONE),
146,
"drift in thousandths of a unit per minute at ten units per second"
);
}
#[test]
fn a_rate_exact_in_nanoseconds_need_not_be_exact_in_the_number_type() {
let billion = 1_000_000_000i128;
let one = i128::from(ONE);
let exact_in_nanos = |hz: i128| billion % hz == 0;
let exact_in_fixed = |hz: i128| one % hz == 0;
assert!(exact_in_nanos(125), "125 Hz divides a second evenly");
assert!(
!exact_in_fixed(125),
"and does not divide 65536, so it is not exact end to end"
);
assert_eq!(one * 1000 / 125, 524_288, "125 Hz is 524.288 raw");
for hz in [1i128, 2, 4, 8, 16, 32, 64, 128, 256, 512] {
assert!(
exact_in_nanos(hz) && exact_in_fixed(hz),
"{hz} Hz should be exact in both representations"
);
}
assert_eq!(one / 64, 1024, "64 Hz in raw units");
assert_eq!(one / 512, 128, "512 Hz in raw units");
assert!(exact_in_fixed(1024), "1024 divides 65536");
assert!(
!exact_in_nanos(1024),
"but not a second, so the exact rates stop at 512 Hz"
);
}
#[test]
fn a_timestep_is_exact_exactly_when_its_nanoseconds_divide_by_the_fifth_power() {
let billion = 1_000_000_000i128;
let one = i128::from(ONE);
let condition = 1_953_125i128;
assert_eq!(condition * 512, billion, "5^9 times 2^9 is a second");
let exact = |nanos: i128| nanos * one % billion == 0;
for hz in [1i128, 24, 30, 50, 60, 64, 100, 120, 125, 128, 240, 256, 512] {
if billion % hz != 0 {
continue; }
let nanos = billion / hz;
assert_eq!(
exact(nanos),
nanos % condition == 0,
"{hz} Hz ({nanos} ns): the multiple-of-1953125 condition must decide exactness"
);
}
assert_eq!(billion / 512, condition, "512 Hz is exactly one multiple");
assert!(
(billion / 125) % condition != 0,
"125 Hz divides a second and is not exact in the number type"
);
}
#[test]
fn segmentation_does_not_bound_slide_creep() {
let creep = |displacement: i64, segments: i64, n: i64| {
let piece = displacement / segments;
segments * n * (2 + piece / 8192)
};
let displacement = 100 * ONE;
let whole = creep(displacement, 1, 4);
for segments in [2i64, 4, 10, 50] {
let cut = creep(displacement, segments, 4);
assert!(
cut >= whole,
"cutting into {segments} pieces gave {cut} raw against {whole} for one — segmentation must never reduce creep, or this test has the arithmetic wrong"
);
}
assert!(
creep(displacement, 50, 4) > creep(displacement, 1, 4),
"more segments must cost more, because each pays the constant term again"
);
let cap = |skin: i64, tolerance: i64, n: i64| 8192 * ((skin - tolerance) / n - 2);
for &(skin, tolerance, n) in &[
(65536i64, 1024i64, 4i64),
(4096, 64, 8),
(1024, 16, 4),
(600, 8, 2),
] {
let l_max = cap(skin, tolerance, n);
let accumulated = n * (2 + l_max / 8192);
let final_clearance = skin - accumulated;
assert!(
final_clearance < skin - tolerance,
"the superseded cap must fail the property, or nothing was learned"
);
assert_eq!(
final_clearance, tolerance,
"skin {skin}, tolerance {tolerance}, {n} iterations"
);
}
}
#[test]
fn a_length_saturates_instead_of_going_negative() {
let below = Fixed::from_bits(6_000_000_000_000_000_000);
let before = renew_fixed::saturations();
let length = Vec2::new(below, below).length();
assert!(
length.to_bits() > 0,
"a length below the threshold came back {} raw",
length.to_bits()
);
assert_eq!(
renew_fixed::saturations().0,
before.0,
"a length well inside the range recorded a saturation"
);
for raw in [
6_600_000_000_000_000_000i64,
7_000_000_000_000_000_000,
8_000_000_000_000_000_000,
i64::MAX,
] {
let component = Fixed::from_bits(raw);
let before = renew_fixed::saturations();
let length = Vec2::new(component, component).length();
assert!(
length.to_bits() > 0,
"a component of {raw} raw gave a length of {} raw — a distance less than nothing",
length.to_bits()
);
assert_eq!(
length.to_bits(),
i64::MAX,
"a component of {raw} raw did not saturate"
);
assert!(
renew_fixed::saturations().0 > before.0,
"a component of {raw} raw saturated without recording it"
);
}
}