use super::Q8E0;
use crate::P8E0;
use core::ops;
crate::macros::quire_add_sub!(P8E0, Q8E0);
crate::macros::quire_add_sub_array!(P8E0, Q8E0, 1, 2, 3, 4);
pub(super) fn fdp(q: &mut Q8E0, mut ui_a: u8, mut ui_b: u8, plus: bool) {
let uq_z1 = q.to_bits();
if q.is_nar() || ui_a == 0x80 || ui_b == 0x80 {
*q = Q8E0::NAR;
return;
} else if ui_a == 0 || ui_b == 0 {
return;
}
let sign_a = P8E0::sign_ui(ui_a);
let sign_b = P8E0::sign_ui(ui_b);
let sign_z2 = sign_a ^ sign_b;
if sign_a {
ui_a = ui_a.wrapping_neg();
}
if sign_b {
ui_b = ui_b.wrapping_neg();
}
let (mut k_a, frac_a) = P8E0::separate_bits(ui_a);
let (k_b, frac_b) = P8E0::separate_bits(ui_b);
k_a += k_b;
let frac32_z = ((frac_a as u32) * (frac_b as u32)) << 16;
let shift_right = 18 - k_a;
let mut uq_z2 = frac32_z >> shift_right;
if !(sign_z2 ^ plus) {
uq_z2 = uq_z2.wrapping_neg();
}
let uq_z = uq_z2.wrapping_add(uq_z1);
let q_z = Q8E0::from_bits(uq_z);
*q = if q_z.is_nar() { Q8E0::ZERO } else { q_z }
}
pub(super) fn fdp_one(q: &mut Q8E0, mut ui_a: u8, plus: bool) {
let uq_z1 = q.to_bits();
if q.is_nar() || ui_a == 0x80 {
*q = Q8E0::NAR;
return;
} else if ui_a == 0 {
return;
}
let sign_a = P8E0::sign_ui(ui_a);
let sign_z2 = sign_a ^ false;
if sign_a {
ui_a = ui_a.wrapping_neg();
}
let (k_a, frac_a) = P8E0::separate_bits(ui_a);
let mut uq_z2 = ((frac_a as u32) << 23) >> (18 - k_a);
if !(sign_z2 ^ plus) {
uq_z2 = uq_z2.wrapping_neg();
}
let uq_z = uq_z2.wrapping_add(uq_z1);
let q_z = Q8E0::from_bits(uq_z);
*q = if q_z.is_nar() { Q8E0::ZERO } else { q_z }
}
#[test]
fn test_quire_mul_add() {
use rand::Rng;
let mut rng = rand::thread_rng();
for _ in 0..crate::NTESTS8 {
let p_a: P8E0 = rng.gen();
let p_b: P8E0 = rng.gen();
let p_c: P8E0 = rng.gen();
let f_a = f64::from(p_a);
let f_b = f64::from(p_b);
let f_c = f64::from(p_c);
let mut q = Q8E0::init();
q += (p_a, p_b);
q += p_c;
let p = q.to_posit();
let f = f_a.mul_add(f_b, f_c);
assert_eq!(p, P8E0::from(f));
}
}
#[test]
fn test_quire_mul_sub() {
use rand::Rng;
let mut rng = rand::thread_rng();
for _ in 0..crate::NTESTS8 {
let p_a: P8E0 = rng.gen();
let p_b: P8E0 = rng.gen();
let p_c: P8E0 = rng.gen();
let f_a = f64::from(p_a);
let f_b = f64::from(p_b);
let f_c = f64::from(p_c);
let mut q = Q8E0::init();
q -= (p_a, p_b);
q += p_c;
let p = q.to_posit();
let f = (-f_a).mul_add(f_b, f_c);
assert_eq!(p, P8E0::from(f));
}
}