bigfixed/
digit.rs

1// Digit specifies u* arithmetic (wrapping) from one of the native integer types. It could be hard coded as u32 or u64 but
2// the smaller types u16/u8 are easier to work with while developing and testing. Hence which one is in use is decided via this macro.
3
4use paste::paste;
5
6macro_rules! build_digit {
7    ($bits: expr, $double_bits: expr) => {
8        paste!{
9            pub const DIGITBITS: usize = $bits;
10            pub const DIGITBYTES: usize = DIGITBITS / 8;
11            pub type Digit = [<u $bits>];
12            pub type SignedDigit = [<i $bits>];
13            
14            pub const DOUBLEBITS: usize = $double_bits;
15            pub const DOUBLEBYTES: usize = 2*DIGITBYTES;
16            pub type DoubleDigit = [<u $double_bits>];
17            pub type SignedDoubleDigit = [<i $double_bits>];
18
19            pub const ALLONES: Digit = (-1 as SignedDigit) as Digit;
20            pub const GREATESTBIT: Digit = 1 << (DIGITBITS - 1);
21
22            pub fn digit_from_bytes(bytes: &[u8]) -> Digit {
23                Digit::from_le_bytes(bytes.try_into().unwrap())
24            }
25            
26            #[macro_export]
27            macro_rules! add {
28                ($a: expr, $b: expr, $result: expr, $carry: expr) => {
29                    let res = ($a as DoubleDigit) + ($b as DoubleDigit);
30                    $result = res as Digit;
31                    $carry = (res >> DIGITBITS) as Digit;
32                };
33                ($a: expr, $b: expr, $result: expr) => {
34                    let res = ($a as Double) + ($b as Double);
35                    $result = res as Digit;
36                };
37            }
38            
39            pub(crate) use add;
40            
41            #[macro_export]
42            macro_rules! mul {
43                ($a: expr, $b: expr, $result: expr, $carry: expr) => {
44                    let res = ($a as DoubleDigit) * ($b as DoubleDigit);
45                    $result = res as Digit;
46                    $carry = (res >> DIGITBITS) as Digit;
47                };
48                ($a: expr, $b: expr, $result: expr) => {
49                    let res = ($a as Double) * ($b as Double);
50                    $result = res as Digit;
51                };
52            }
53            
54            pub(crate) use mul;
55
56            #[macro_export]
57            macro_rules! div {
58                ($dividend_high: expr, $dividend_low: expr, $divisor: expr, $quot: expr) => {
59                    let dividend = (($dividend_high as DoubleDigit) << DIGITBITS) | ($dividend_low as DoubleDigit);
60                    let divisor = $divisor as DoubleDigit;
61                    $quot = (dividend / divisor) as Digit;
62                };
63            }
64            pub(crate) use div;
65        }
66    };
67}
68
69build_digit!(16, 32);
70
71#[macro_export]
72macro_rules! binary_formatter {
73    () => {
74        "{:#018b}" // digit bits + 2 for 0b
75    };
76}
77
78pub(crate) use binary_formatter;