bonfida_utils/
fp_math.rs

1use std::convert::TryInto;
2
3pub const FP_32_ONE: u64 = 1 << 32;
4
5/// a is fp0, b is fp32 and result is a/b fp0
6pub fn fp32_div(a: u64, b_fp32: u64) -> Option<u64> {
7    ((a as u128) << 32)
8        .checked_div(b_fp32 as u128)
9        .and_then(|x| x.try_into().ok())
10}
11
12/// a is fp0, b is fp32 and result is a*b fp0
13pub fn fp32_mul_floor(a: u64, b_fp32: u64) -> Option<u64> {
14    (a as u128)
15        .checked_mul(b_fp32 as u128)
16        .and_then(|x| (x >> 32).try_into().ok())
17}
18
19/// a is fp0, b is fp32 and result is a*b fp0
20pub fn fp32_mul_ceil(a: u64, b_fp32: u64) -> Option<u64> {
21    (a as u128)
22        .checked_mul(b_fp32 as u128)
23        .and_then(fp32_ceil_util)
24        .and_then(|x| (x >> 32).try_into().ok())
25}
26
27/// a is fp0, b is fp32 and result is a/b fp0
28pub fn ifp32_div(a: i64, b_fp32: u64) -> Option<i64> {
29    ((a.unsigned_abs() as u128) << 32)
30        .checked_div(b_fp32 as u128)
31        .and_then(|x| x.try_into().ok())
32        .map(|x: i64| a.signum() * x)
33}
34
35/// a is fp0, b is fp32 and result is a*b fp0
36pub fn ifp32_mul_floor(a: i64, b_fp32: u64) -> Option<i64> {
37    (a.unsigned_abs() as u128)
38        .checked_mul(b_fp32 as u128)
39        .and_then(|x| (x >> 32).try_into().ok())
40        .map(|x: i64| a.signum() * x)
41}
42
43/// a is fp0, b is fp32 and result is a*b fp0
44pub fn ifp32_mul_ceil(a: i64, b_fp32: u64) -> Option<i64> {
45    (a.unsigned_abs() as u128)
46        .checked_mul(b_fp32 as u128)
47        .and_then(fp32_ceil_util)
48        .and_then(|x| (x >> 32).try_into().ok())
49        .map(|x: i64| a.signum() * x)
50}
51
52/// a is fp0, b is fp64 and result is a/b fp0
53pub fn fp64_div(a: u64, b_fp64: u64) -> Option<u64> {
54    ((a as u128) << 64)
55        .checked_div(b_fp64 as u128)
56        .and_then(|x| x.try_into().ok())
57}
58
59/// a is fp0, b is fp64 and result is a*b fp0
60pub fn fp64_mul_floor(a: u64, b_fp64: u64) -> Option<u64> {
61    (a as u128)
62        .checked_mul(b_fp64 as u128)
63        .map(|x| (x >> 64))
64        .and_then(|x| x.try_into().ok())
65}
66
67/// a is fp0, b is fp64 and result is a*b fp0
68pub fn fp64_mul_ceil(a: u64, b_fp64: u64) -> Option<u64> {
69    (a as u128)
70        .checked_mul(b_fp64 as u128)
71        .map(|x| (x >> 64))
72        .and_then(fp64_ceil_util)
73        .and_then(|x| x.try_into().ok())
74}
75
76#[inline(always)]
77fn fp32_ceil_util(x_fp32: u128) -> Option<u128> {
78    let add_one = (!(x_fp32 as u32)).wrapping_add(1) as u128;
79    x_fp32.checked_add(add_one)
80}
81
82#[inline(always)]
83fn fp64_ceil_util(x_fp64: u128) -> Option<u128> {
84    let add_one = (!(x_fp64 as u64)).wrapping_add(1) as u128;
85    x_fp64.checked_add(add_one)
86}
87
88#[test]
89fn test() {
90    // fp32_div
91    assert_eq!(fp32_div(124345678765454, 45654 << 32).unwrap(), 2723653541);
92    assert_eq!(fp32_div(124345678765454, 6787654 << 32).unwrap(), 18319389);
93
94    // fp32_mul
95    assert_eq!(
96        fp32_mul_floor(5676543, 6787654 << 32).unwrap(),
97        38530409800122
98    );
99    assert_eq!(fp32_mul_floor(12454, 45654 << 32).unwrap(), 568574916);
100    assert_eq!(fp32_mul_floor(5, 1 << 31).unwrap(), 2);
101    assert_eq!(
102        fp32_mul_ceil(5676543, 6787654 << 32).unwrap(),
103        38530409800122
104    );
105    assert_eq!(fp32_mul_ceil(12454, 45654 << 32).unwrap(), 568574916);
106    assert_eq!(fp32_mul_ceil(5, 1 << 31).unwrap(), 3);
107
108    // ifp32_div
109    assert_eq!(ifp32_div(124345678765454, 6787654 << 32).unwrap(), 18319389);
110    assert_eq!(ifp32_div(124345678765454, 45654 << 32).unwrap(), 2723653541);
111
112    // ifp32_mul
113    assert_eq!(
114        ifp32_mul_floor(5676543, 6787654 << 32).unwrap(),
115        38530409800122
116    );
117    assert_eq!(ifp32_mul_floor(12454, 45654 << 32).unwrap(), 568574916);
118
119    // fp64_div
120    assert_eq!(fp64_div(5676543, 345678909876543456).unwrap(), 302921968);
121    assert_eq!(fp64_div(12454, 345678909876543456).unwrap(), 664592);
122
123    // fp64_mul
124    assert_eq!(fp64_mul_floor(5676543, 345678909876543456).unwrap(), 106374);
125    assert_eq!(fp64_mul_floor(12454, 345678909876543456).unwrap(), 233)
126}