multiply_by_rational_with_rounding/
multiply_by_rational_with_rounding.rs1use fraction::prelude::BigFraction as Fraction;
33use honggfuzz::fuzz;
34use sp_arithmetic::{MultiplyRational, Rounding, Rounding::*};
35
36fn main() {
38 loop {
39 fuzz!(|data: (u128, u128, u128, ArbitraryRounding)| {
40 let (f, n, d, r) = (data.0, data.1, data.2, data.3 .0);
41
42 check::<u8>(f as u8, n as u8, d as u8, r);
43 check::<u16>(f as u16, n as u16, d as u16, r);
44 check::<u32>(f as u32, n as u32, d as u32, r);
45 check::<u64>(f as u64, n as u64, d as u64, r);
46 check::<u128>(f, n, d, r);
47 })
48 }
49}
50
51fn check<N>(f: N, n: N, d: N, r: Rounding)
52where
53 N: MultiplyRational + Into<u128> + Copy + core::fmt::Debug,
54{
55 let Some(got) = f.multiply_rational(n, d, r) else { return };
56
57 let (ae, be, ce) =
58 (Fraction::from(f.into()), Fraction::from(n.into()), Fraction::from(d.into()));
59 let want = round(ae * be / ce, r);
60
61 assert_eq!(
62 Fraction::from(got.into()),
63 want,
64 "{:?} * {:?} / {:?} = {:?} != {:?}",
65 f,
66 n,
67 d,
68 got,
69 want
70 );
71}
72
73fn round(f: Fraction, r: Rounding) -> Fraction {
75 match r {
76 Up => f.ceil(),
77 NearestPrefUp =>
78 if f.fract() < Fraction::from(0.5) {
79 f.floor()
80 } else {
81 f.ceil()
82 },
83 Down => f.floor(),
84 NearestPrefDown =>
85 if f.fract() > Fraction::from(0.5) {
86 f.ceil()
87 } else {
88 f.floor()
89 },
90 }
91}
92
93struct ArbitraryRounding(Rounding);
95impl arbitrary::Arbitrary<'_> for ArbitraryRounding {
96 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
97 Ok(Self(match u.int_in_range(0..=3).unwrap() {
98 0 => Up,
99 1 => NearestPrefUp,
100 2 => Down,
101 3 => NearestPrefDown,
102 _ => unreachable!(),
103 }))
104 }
105}