clean arithmetic and unify names with the new api (#8581)

This commit is contained in:
Kian Paimani
2021-04-09 16:36:06 +02:00
committed by GitHub
parent 7e59d172b8
commit 373e3a4ddc
6 changed files with 30 additions and 32 deletions
+23 -27
View File
@@ -33,6 +33,10 @@ const SHIFT: usize = 32;
/// short form of _Base_. Analogous to the value 10 in base-10 decimal numbers.
const B: Double = Single::max_value() as Double + 1;
static_assertions::const_assert!(
sp_std::mem::size_of::<Double>() - sp_std::mem::size_of::<Single>() == SHIFT / 8
);
/// Splits a [`Double`] limb number into a tuple of two [`Single`] limb numbers.
pub fn split(a: Double) -> (Single, Single) {
let al = a as Single;
@@ -187,6 +191,7 @@ impl BigUint {
let u = Double::from(self.checked_get(j).unwrap_or(0));
let v = Double::from(other.checked_get(j).unwrap_or(0));
let s = u + v + k;
// proof: any number % B will fit into `Single`.
w.set(j, (s % B) as Single);
k = s / B;
}
@@ -209,28 +214,24 @@ impl BigUint {
let s = {
let u = Double::from(self.checked_get(j).unwrap_or(0));
let v = Double::from(other.checked_get(j).unwrap_or(0));
let mut needs_borrow = false;
let mut t = 0;
if let Some(v1) = u.checked_sub(v) {
if let Some(v2) = v1.checked_sub(k) {
t = v2;
k = 0;
} else {
needs_borrow = true;
}
if let Some(v2) = u.checked_sub(v).and_then(|v1| v1.checked_sub(k)) {
// no borrow is needed. u - v - k can be computed as-is
let t = v2;
k = 0;
t
} else {
needs_borrow = true;
}
if needs_borrow {
t = u + B - v - k;
// borrow is needed. Add a `B` to u, before subtracting.
// PROOF: addition: `u + B < 2*B`, thus can fit in double.
// PROOF: subtraction: if `u - v - k < 0`, then `u + B - v - k < B`.
// NOTE: the order of operations is critical to ensure underflow won't happen.
let t = u + B - v - k;
k = 1;
t
}
t
};
// PROOF: t either comes from `v2`, or from `u + B - v - k`. The former is
// trivial. The latter will not overflow this branch will only happen if the sum of
// `u - v - k` part has been negative, hence `u + B - v - k < B`.
w.set(j, s as Single);
}
@@ -264,10 +265,9 @@ impl BigUint {
let mut k = 0;
for i in 0..m {
// PROOF: (B1) × (B1) + (B1) + (B1) = B^2 1 < B^2. addition is safe.
let t =
mul_single(self.get(j), other.get(i))
+ Double::from(w.get(i + j))
+ Double::from(k);
let t = mul_single(self.get(j), other.get(i))
+ Double::from(w.get(i + j))
+ Double::from(k);
w.set(i + j, (t % B) as Single);
// PROOF: (B^2 - 1) / B < B. conversion is safe.
k = (t / B) as Single;
@@ -580,12 +580,6 @@ pub mod tests {
BigUint { digits: vec![1; n] }
}
#[test]
fn shift_check() {
let shift = sp_std::mem::size_of::<Double>() - sp_std::mem::size_of::<Single>();
assert_eq!(shift * 8, SHIFT);
}
#[test]
fn split_works() {
let a = SHIFT / 2;
@@ -732,12 +726,14 @@ pub mod tests {
let c = BigUint { digits: vec![1, 1, 2] };
let d = BigUint { digits: vec![0, 2] };
let e = BigUint { digits: vec![0, 1, 1, 2] };
let f = BigUint { digits: vec![7, 8] };
assert!(a.clone().div(&b, true).is_none());
assert!(c.clone().div(&a, true).is_none());
assert!(c.clone().div(&d, true).is_none());
assert!(e.clone().div(&a, true).is_none());
assert!(f.clone().div(&b, true).is_none());
assert!(c.clone().div(&b, true).is_some());
}
@@ -381,7 +381,7 @@ macro_rules! implement_fixed {
}
#[cfg(any(feature = "std", test))]
pub fn to_fraction(self) -> f64 {
pub fn to_float(self) -> f64 {
self.0 as f64 / <Self as FixedPointNumber>::DIV as f64
}
}