Skip to main content

ironwork_numeric/
sign.rs

1//! Signs of packed and zoned items under NUMPROC. Arithmetic results take the preferred sign under
2//! either setting; the settings differ in whether a sign is repaired on the way through a MOVE and
3//! whether a comparison is algebraic. See [`crate::assumptions::PFD_MOVES_BYTES`] and
4//! [`crate::assumptions::PFD_COMPARES_LOGICALLY`].
5
6use crate::options::Numproc;
7use std::cmp::Ordering;
8use zarch::check::ProgramCheck;
9use zarch::decimal::{self, MINUS, PLUS, UNSIGNED};
10
11pub const fn preferred(negative: bool, signed: bool) -> u8 {
12    match (signed, negative) {
13        (false, _) => UNSIGNED,
14        (true, true) => MINUS,
15        (true, false) => PLUS,
16    }
17}
18
19/// A MOVE between packed items of the same length and scale.
20pub fn move_packed(source: &[u8], receiver_signed: bool, numproc: Numproc) -> Vec<u8> {
21    let mut out = source.to_vec();
22    if numproc == Numproc::Nopfd {
23        let last = out.last_mut().expect("a packed item is at least one byte");
24        let negative = decimal::is_minus(*last & 0xF);
25        *last = (*last & 0xF0) | preferred(negative, receiver_signed);
26    }
27    out
28}
29
30/// A comparison between packed items of the same length and scale.
31pub fn compare_packed(a: &[u8], b: &[u8], numproc: Numproc) -> Result<Ordering, ProgramCheck> {
32    match numproc {
33        Numproc::Nopfd => Ok(decimal::cp(a, b)?.ordering().unwrap_or(Ordering::Greater)),
34        Numproc::Pfd => Ok(a.cmp(b)),
35    }
36}
37
38#[cfg(test)]
39mod tests {
40    use super::*;
41
42    #[test]
43    fn nopfd_repairs_the_sign_on_a_move_and_pfd_copies_it() {
44        assert_eq!(move_packed(&[0x12, 0x3A], true, Numproc::Nopfd), [0x12, 0x3C]);
45        assert_eq!(move_packed(&[0x12, 0x3B], true, Numproc::Nopfd), [0x12, 0x3D]);
46        assert_eq!(move_packed(&[0x12, 0x3C], false, Numproc::Nopfd), [0x12, 0x3F]);
47        assert_eq!(move_packed(&[0x12, 0x3A], true, Numproc::Pfd), [0x12, 0x3A]);
48    }
49
50    #[test]
51    fn plus_signs_f_and_c_are_equal_only_under_nopfd() {
52        assert_eq!(compare_packed(&[0x1F], &[0x1C], Numproc::Nopfd), Ok(Ordering::Equal));
53        assert_eq!(compare_packed(&[0x1F], &[0x1C], Numproc::Pfd), Ok(Ordering::Greater));
54    }
55
56    #[test]
57    fn nopfd_comparison_of_an_invalid_sign_is_a_data_exception() {
58        assert_eq!(compare_packed(&[0x14], &[0x1C], Numproc::Nopfd), Err(ProgramCheck::Data));
59    }
60}