px_native/cipher/remap.rs
1//! `vM(t, n, e, r, g)` — linear remap from `[n, e]` to `[r, g]`,
2//! `Math.floor`-rounded. JS reference:
3//!
4//! ```text
5//! function vM(t, n, e, r, g) {
6//! return Math.floor((t - n) / (e - n) * (g - r) + r);
7//! }
8//! ```
9//!
10//! All call sites we observe pass non-negative integers and `n < e`,
11//! so the integer-cast path is exact; we still go through `f64` to
12//! match JS rounding when intermediate products overflow u32.
13
14#[inline]
15pub fn v_m(t: i64, n: i64, e: i64, r: i64, g: i64) -> i64 {
16 let denom = (e - n) as f64;
17 let numer = (t - n) as f64;
18 let scale = (g - r) as f64;
19 let bias = r as f64;
20 (numer / denom * scale + bias).floor() as i64
21}
22
23#[cfg(test)]
24mod tests {
25 use super::*;
26
27 #[test]
28 fn remap_midpoint() {
29 assert_eq!(v_m(50, 0, 100, 0, 10), 5);
30 }
31
32 #[test]
33 fn remap_zero_zero() {
34 assert_eq!(v_m(0, 0, 1, 0, 1), 0);
35 }
36}