1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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;
    }

    //max pos (sign plus and minus)
    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;

    //default dot is between bit 19 and 20, extreme left bit is bit 0. Last right bit is bit 31.
    //Scale = 2^es * k + e  => 2k + e // firstPost = 19-k_a, shift = firstPos -1 (because frac32_z start from 2nd bit)
    //int firstPos = 19 - k_a;
    let shift_right = 18 - k_a;

    let mut uq_z2 = frac32_z >> shift_right;

    if !(sign_z2 ^ plus) {
        uq_z2 = uq_z2.wrapping_neg();
    }

    //Addition
    let uq_z = uq_z2.wrapping_add(uq_z1);

    //Exception handling
    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;
    }

    //max pos (sign plus and minus)
    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();
    }

    //Addition
    let uq_z = uq_z2.wrapping_add(uq_z1);

    //Exception handling
    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));
    }
}