//! Right-shifts the normalized remainder to recover the true remainder after division.
use super::KnuthD;

impl KnuthD {
    /// Right-shifts the normalized remainder in `un[0..n]` by `self.s` bits
    /// to undo the normalization applied during construction.
    ///
    /// Returns a 4-element little-endian array with the true remainder.
    /// Only the first `self.n` elements are meaningful; the rest are zero.
    pub(super) fn unnormalize(&self, un: &[u64; 9]) -> [u64; 4] {
        let mut rem = [0u64; 4];
        if self.s > 0 {
            for i in 0..self.n.saturating_sub(1) {
                rem[i] = (un[i] >> self.s) | (un[i + 1] << (64 - self.s));
            }
            if self.n > 0 {
                rem[self.n - 1] = un[self.n - 1] >> self.s;
            }
        } else {
            rem[..self.n].copy_from_slice(&un[..self.n]);
        }
        rem
    }
}

#[cfg(test)]
mod ai_tests {
    use super::*;

    /// Zero shift copies the input unchanged.
    #[test]
    fn zero_shift() {
        let kd = KnuthD::new(&[0, 1u64 << 63, 0, 0], 2);
        assert_eq!(kd.s, 0);
        let un = [42u64, 99, 0, 0, 0, 0, 0, 0, 0];
        let rem = kd.unnormalize(&un);
        assert_eq!(rem, [42, 99, 0, 0]);
    }

    /// Unnormalize correctly right-shifts a manually constructed remainder.
    #[test]
    fn round_trip() {
        let kd = KnuthD::new(&[1, 1, 0, 0], 2);
        // s = 63. Manually shift [7, 1] left by 63 bits into un[0..2].
        // 7 << 63 = 0x8000000000000000 (only bit 0 of 7 survives in u64)
        // (1 << 63) | (7 >> 1) = 0x8000000000000003
        let un = [
            7u64 << kd.s,
            (1u64 << kd.s) | (7u64 >> (64 - kd.s)),
            0,
            0,
            0,
            0,
            0,
            0,
            0,
        ];
        let rem = kd.unnormalize(&un);
        assert_eq!(rem[0], 7);
        assert_eq!(rem[1], 1);
    }

    /// All-zero input stays all zero.
    #[test]
    fn zero_remainder() {
        let kd = KnuthD::new(&[1, 1, 0, 0], 2);
        let un = [0u64; 9];
        assert_eq!(kd.unnormalize(&un), [0u64; 4]);
    }
}
