Accept new Phragmén solutions if they are epsilon better + Better pre-inclusion checks. (#6173)

* part1: Accept inly epsilon better solutions

* Fix pre-dispatch check

* Fix build

* review grumbles

* Epsilon -> Threshold
This commit is contained in:
Kian Paimani
2020-06-02 17:22:56 +02:00
committed by GitHub
parent 6547d7a09a
commit 0eec4bb795
14 changed files with 310 additions and 46 deletions
+78 -1
View File
@@ -41,12 +41,89 @@ mod fixed;
mod rational128;
pub use fixed::{FixedPointNumber, Fixed64, Fixed128, FixedPointOperand};
pub use per_things::{PerThing, Percent, PerU16, Permill, Perbill, Perquintill};
pub use per_things::{PerThing, InnerOf, Percent, PerU16, Permill, Perbill, Perquintill};
pub use rational128::Rational128;
use sp_std::cmp::Ordering;
/// Trait for comparing two numbers with an threshold.
///
/// Returns:
/// - `Ordering::Greater` if `self` is greater than `other + threshold`.
/// - `Ordering::Less` if `self` is less than `other - threshold`.
/// - `Ordering::Equal` otherwise.
pub trait ThresholdOrd<T> {
/// Compare if `self` is `threshold` greater or less than `other`.
fn tcmp(&self, other: &T, epsilon: T) -> Ordering;
}
impl<T> ThresholdOrd<T> for T
where
T: Ord + PartialOrd + Copy + Clone + traits::Zero + traits::Saturating,
{
fn tcmp(&self, other: &T, threshold: T) -> Ordering {
// early exit.
if threshold.is_zero() {
return self.cmp(&other)
}
let upper_bound = other.saturating_add(threshold);
let lower_bound = other.saturating_sub(threshold);
if upper_bound <= lower_bound {
// defensive only. Can never happen.
self.cmp(&other)
} else {
// upper_bound is guaranteed now to be bigger than lower.
match (self.cmp(&lower_bound), self.cmp(&upper_bound)) {
(Ordering::Greater, Ordering::Greater) => Ordering::Greater,
(Ordering::Less, Ordering::Less) => Ordering::Less,
_ => Ordering::Equal,
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use sp_std::cmp::Ordering;
#[test]
fn epsilon_ord_works() {
let b = 115u32;
let e = Perbill::from_percent(10).mul_ceil(b);
// [115 - 11,5 (103,5), 115 + 11,5 (126,5)] is all equal
assert_eq!(103u32.tcmp(&b, e), Ordering::Equal);
assert_eq!(104u32.tcmp(&b, e), Ordering::Equal);
assert_eq!(115u32.tcmp(&b, e), Ordering::Equal);
assert_eq!(120u32.tcmp(&b, e), Ordering::Equal);
assert_eq!(126u32.tcmp(&b, e), Ordering::Equal);
assert_eq!(127u32.tcmp(&b, e), Ordering::Equal);
assert_eq!(128u32.tcmp(&b, e), Ordering::Greater);
assert_eq!(102u32.tcmp(&b, e), Ordering::Less);
}
#[test]
fn epsilon_ord_works_with_small_epc() {
let b = 115u32;
// way less than 1 percent. threshold will be zero. Result should be same as normal ord.
let e = Perbill::from_parts(100) * b;
// [115 - 11,5 (103,5), 115 + 11,5 (126,5)] is all equal
assert_eq!(103u32.tcmp(&b, e), 103u32.cmp(&b));
assert_eq!(104u32.tcmp(&b, e), 104u32.cmp(&b));
assert_eq!(115u32.tcmp(&b, e), 115u32.cmp(&b));
assert_eq!(120u32.tcmp(&b, e), 120u32.cmp(&b));
assert_eq!(126u32.tcmp(&b, e), 126u32.cmp(&b));
assert_eq!(127u32.tcmp(&b, e), 127u32.cmp(&b));
assert_eq!(128u32.tcmp(&b, e), 128u32.cmp(&b));
assert_eq!(102u32.tcmp(&b, e), 102u32.cmp(&b));
}
#[test]
fn peru16_rational_does_not_overflow() {