1#![cfg_attr(not(feature = "std"), no_std)]
21
22extern crate alloc;
23
24#[macro_export]
26macro_rules! assert_eq_error_rate {
27 ($x:expr, $y:expr, $error:expr $(,)?) => {
28 assert!(
29 ($x) >= (($y) - ($error)) && ($x) <= (($y) + ($error)),
30 "{:?} != {:?} (with error rate {:?})",
31 $x,
32 $y,
33 $error,
34 );
35 };
36}
37
38pub mod biguint;
39pub mod fixed_point;
40pub mod helpers_128bit;
41pub mod per_things;
42pub mod rational;
43pub mod traits;
44
45pub use fixed_point::{
46 FixedI128, FixedI64, FixedPointNumber, FixedPointOperand, FixedU128, FixedU64,
47};
48pub use per_things::{
49 InnerOf, MultiplyArg, PerThing, PerU16, Perbill, Percent, Permill, Perquintill, RationalArg,
50 ReciprocalArg, Rounding, SignedRounding, UpperOf,
51};
52pub use rational::{MultiplyRational, Rational128, RationalInfinite};
53
54use alloc::vec::Vec;
55use core::{cmp::Ordering, fmt::Debug};
56use traits::{BaseArithmetic, One, SaturatedConversion, Unsigned, Zero};
57
58use codec::{Decode, Encode, MaxEncodedLen};
59use scale_info::TypeInfo;
60
61#[cfg(feature = "serde")]
62use serde::{Deserialize, Serialize};
63
64#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
66#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
67pub enum ArithmeticError {
68 Underflow,
70 Overflow,
72 DivisionByZero,
74}
75
76impl From<ArithmeticError> for &'static str {
77 fn from(e: ArithmeticError) -> &'static str {
78 match e {
79 ArithmeticError::Underflow => "An underflow would occur",
80 ArithmeticError::Overflow => "An overflow would occur",
81 ArithmeticError::DivisionByZero => "Division by zero",
82 }
83 }
84}
85
86pub trait ThresholdOrd<T> {
93 fn tcmp(&self, other: &T, threshold: T) -> Ordering;
95}
96
97impl<T> ThresholdOrd<T> for T
98where
99 T: Ord + PartialOrd + Copy + Clone + traits::Zero + traits::Saturating,
100{
101 fn tcmp(&self, other: &T, threshold: T) -> Ordering {
102 if threshold.is_zero() {
104 return self.cmp(other);
105 }
106
107 let upper_bound = other.saturating_add(threshold);
108 let lower_bound = other.saturating_sub(threshold);
109
110 if upper_bound <= lower_bound {
111 self.cmp(other)
113 } else {
114 match (self.cmp(&lower_bound), self.cmp(&upper_bound)) {
116 (Ordering::Greater, Ordering::Greater) => Ordering::Greater,
117 (Ordering::Less, Ordering::Less) => Ordering::Less,
118 _ => Ordering::Equal,
119 }
120 }
121 }
122}
123
124pub trait Normalizable<T> {
129 fn normalize(&self, targeted_sum: T) -> Result<Vec<T>, &'static str>;
134}
135
136macro_rules! impl_normalize_for_numeric {
137 ($($numeric:ty),*) => {
138 $(
139 impl Normalizable<$numeric> for Vec<$numeric> {
140 fn normalize(&self, targeted_sum: $numeric) -> Result<Vec<$numeric>, &'static str> {
141 normalize(self.as_ref(), targeted_sum)
142 }
143 }
144 )*
145 };
146}
147
148impl_normalize_for_numeric!(u8, u16, u32, u64, u128);
149
150impl<P: PerThing> Normalizable<P> for Vec<P> {
151 fn normalize(&self, targeted_sum: P) -> Result<Vec<P>, &'static str> {
152 let uppers = self.iter().map(|p| <UpperOf<P>>::from(p.deconstruct())).collect::<Vec<_>>();
153
154 let normalized =
155 normalize(uppers.as_ref(), <UpperOf<P>>::from(targeted_sum.deconstruct()))?;
156
157 Ok(normalized
158 .into_iter()
159 .map(|i: UpperOf<P>| P::from_parts(i.saturated_into::<P::Inner>()))
160 .collect())
161 }
162}
163
164pub fn normalize<T>(input: &[T], targeted_sum: T) -> Result<Vec<T>, &'static str>
194where
195 T: Clone + Copy + Ord + BaseArithmetic + Unsigned + Debug,
196{
197 let mut sum = T::zero();
199 for t in input.iter() {
200 sum = sum.checked_add(t).ok_or("sum of input cannot fit in `T`")?;
201 }
202
203 let count = input.len();
205 let count_t: T = count.try_into().map_err(|_| "length of `inputs` cannot fit in `T`")?;
206
207 if count.is_zero() {
209 return Ok(Vec::<T>::new());
210 }
211
212 let diff = targeted_sum.max(sum) - targeted_sum.min(sum);
213 if diff.is_zero() {
214 return Ok(input.to_vec());
215 }
216
217 let needs_bump = targeted_sum > sum;
218 let per_round = diff / count_t;
219 let mut leftover = diff % count_t;
220
221 let mut output_with_idx = input.iter().cloned().enumerate().collect::<Vec<(usize, T)>>();
224 output_with_idx.sort_by_key(|x| x.1);
225
226 if needs_bump {
227 let mut min_index = 0;
231 let threshold = targeted_sum / count_t;
233
234 if !per_round.is_zero() {
235 for _ in 0..count {
236 output_with_idx[min_index].1 = output_with_idx[min_index]
237 .1
238 .checked_add(&per_round)
239 .expect("Proof provided in the module doc; qed.");
240 if output_with_idx[min_index].1 >= threshold {
241 min_index += 1;
242 min_index %= count;
243 }
244 }
245 }
246
247 while !leftover.is_zero() {
249 output_with_idx[min_index].1 = output_with_idx[min_index]
250 .1
251 .checked_add(&T::one())
252 .expect("Proof provided in the module doc; qed.");
253 if output_with_idx[min_index].1 >= threshold {
254 min_index += 1;
255 min_index %= count;
256 }
257 leftover -= One::one();
258 }
259 } else {
260 let mut max_index = count - 1;
264 let threshold = output_with_idx
266 .first()
267 .expect("length of input is greater than zero; it must have a first; qed")
268 .1;
269
270 if !per_round.is_zero() {
271 for _ in 0..count {
272 output_with_idx[max_index].1 =
273 output_with_idx[max_index].1.checked_sub(&per_round).unwrap_or_else(|| {
274 let remainder = per_round - output_with_idx[max_index].1;
275 leftover += remainder;
276 output_with_idx[max_index].1.saturating_sub(per_round)
277 });
278 if output_with_idx[max_index].1 <= threshold {
279 max_index = max_index.checked_sub(1).unwrap_or(count - 1);
280 }
281 }
282 }
283
284 while !leftover.is_zero() {
286 if let Some(next) = output_with_idx[max_index].1.checked_sub(&One::one()) {
287 output_with_idx[max_index].1 = next;
288 if output_with_idx[max_index].1 <= threshold {
289 max_index = max_index.checked_sub(1).unwrap_or(count - 1);
290 }
291 leftover -= One::one();
292 } else {
293 max_index = max_index.checked_sub(1).unwrap_or(count - 1);
294 }
295 }
296 }
297
298 debug_assert_eq!(
299 output_with_idx.iter().fold(T::zero(), |acc, (_, x)| acc + *x),
300 targeted_sum,
301 "sum({:?}) != {:?}",
302 output_with_idx,
303 targeted_sum
304 );
305
306 output_with_idx.sort_by_key(|x| x.0);
308 Ok(output_with_idx.into_iter().map(|(_, t)| t).collect())
309}
310
311#[cfg(test)]
312mod normalize_tests {
313 use super::*;
314
315 #[test]
316 fn work_for_all_types() {
317 macro_rules! test_for {
318 ($type:ty) => {
319 assert_eq!(
320 normalize(vec![8 as $type, 9, 7, 10].as_ref(), 40).unwrap(),
321 vec![10, 10, 10, 10],
322 );
323 };
324 }
325 test_for!(u128);
327 test_for!(u64);
328 test_for!(u32);
329 test_for!(u16);
330 test_for!(u8);
331 }
332
333 #[test]
334 fn fails_on_if_input_sum_large() {
335 assert!(normalize(vec![1u8; 255].as_ref(), 10).is_ok());
336 assert_eq!(normalize(vec![1u8; 256].as_ref(), 10), Err("sum of input cannot fit in `T`"));
337 }
338
339 #[test]
340 fn does_not_fail_on_subtraction_overflow() {
341 assert_eq!(normalize(vec![1u8, 100, 100].as_ref(), 10).unwrap(), vec![1, 9, 0]);
342 assert_eq!(normalize(vec![1u8, 8, 9].as_ref(), 1).unwrap(), vec![0, 1, 0]);
343 }
344
345 #[test]
346 fn works_for_vec() {
347 assert_eq!(vec![8u32, 9, 7, 10].normalize(40).unwrap(), vec![10u32, 10, 10, 10]);
348 }
349
350 #[test]
351 fn works_for_per_thing() {
352 assert_eq!(
353 vec![Perbill::from_percent(33), Perbill::from_percent(33), Perbill::from_percent(33)]
354 .normalize(Perbill::one())
355 .unwrap(),
356 vec![
357 Perbill::from_parts(333333334),
358 Perbill::from_parts(333333333),
359 Perbill::from_parts(333333333)
360 ]
361 );
362
363 assert_eq!(
364 vec![Perbill::from_percent(20), Perbill::from_percent(15), Perbill::from_percent(30)]
365 .normalize(Perbill::one())
366 .unwrap(),
367 vec![
368 Perbill::from_parts(316666668),
369 Perbill::from_parts(383333332),
370 Perbill::from_parts(300000000)
371 ]
372 );
373 }
374
375 #[test]
376 fn can_work_for_peru16() {
377 assert_eq!(
381 vec![PerU16::from_percent(40), PerU16::from_percent(40), PerU16::from_percent(40)]
382 .normalize(PerU16::one())
383 .unwrap(),
384 vec![
385 PerU16::from_parts(21845), PerU16::from_parts(21845), PerU16::from_parts(21845) ]
389 );
390 }
391
392 #[test]
393 fn normalize_works_all_le() {
394 assert_eq!(normalize(vec![8u32, 9, 7, 10].as_ref(), 40).unwrap(), vec![10, 10, 10, 10]);
395
396 assert_eq!(normalize(vec![7u32, 7, 7, 7].as_ref(), 40).unwrap(), vec![10, 10, 10, 10]);
397
398 assert_eq!(normalize(vec![7u32, 7, 7, 10].as_ref(), 40).unwrap(), vec![11, 11, 8, 10]);
399
400 assert_eq!(normalize(vec![7u32, 8, 7, 10].as_ref(), 40).unwrap(), vec![11, 8, 11, 10]);
401
402 assert_eq!(normalize(vec![7u32, 7, 8, 10].as_ref(), 40).unwrap(), vec![11, 11, 8, 10]);
403 }
404
405 #[test]
406 fn normalize_works_some_ge() {
407 assert_eq!(normalize(vec![8u32, 11, 9, 10].as_ref(), 40).unwrap(), vec![10, 11, 9, 10]);
408 }
409
410 #[test]
411 fn always_inc_min() {
412 assert_eq!(normalize(vec![10u32, 7, 10, 10].as_ref(), 40).unwrap(), vec![10, 10, 10, 10]);
413 assert_eq!(normalize(vec![10u32, 10, 7, 10].as_ref(), 40).unwrap(), vec![10, 10, 10, 10]);
414 assert_eq!(normalize(vec![10u32, 10, 10, 7].as_ref(), 40).unwrap(), vec![10, 10, 10, 10]);
415 }
416
417 #[test]
418 fn normalize_works_all_ge() {
419 assert_eq!(normalize(vec![12u32, 11, 13, 10].as_ref(), 40).unwrap(), vec![10, 10, 10, 10]);
420
421 assert_eq!(normalize(vec![13u32, 13, 13, 13].as_ref(), 40).unwrap(), vec![10, 10, 10, 10]);
422
423 assert_eq!(normalize(vec![13u32, 13, 13, 10].as_ref(), 40).unwrap(), vec![12, 9, 9, 10]);
424
425 assert_eq!(normalize(vec![13u32, 12, 13, 10].as_ref(), 40).unwrap(), vec![9, 12, 9, 10]);
426
427 assert_eq!(normalize(vec![13u32, 13, 12, 10].as_ref(), 40).unwrap(), vec![9, 9, 12, 10]);
428 }
429}
430
431#[cfg(test)]
432mod per_and_fixed_examples {
433 use super::*;
434
435 #[docify::export]
436 #[test]
437 fn percent_mult() {
438 let percent = Percent::from_rational(5u32, 100u32); let five_percent_of_100 = percent * 100u32; assert_eq!(five_percent_of_100, 5)
441 }
442 #[docify::export]
443 #[test]
444 fn perbill_example() {
445 let p = Perbill::from_percent(80);
446 assert_eq!(p.deconstruct(), 800000000);
449 }
450
451 #[docify::export]
452 #[test]
453 fn percent_example() {
454 let percent = Percent::from_rational(190u32, 400u32);
455 assert_eq!(percent.deconstruct(), 47);
456 }
457
458 #[docify::export]
459 #[test]
460 fn fixed_u64_block_computation_example() {
461 let price = FixedU64::from_rational(5u128, 10u128);
465
466 assert_eq!(price, FixedU64::from_float(0.5));
468
469 let price = FixedU64::from_rational(19u128, 10u128);
477
478 assert_eq!(price, FixedU64::from_float(1.9));
480 }
481
482 #[docify::export]
483 #[test]
484 fn fixed_u64() {
485 let rational_1 = FixedU64::from_rational(10, 5); let rational_2 = FixedU64::from_rational_with_rounding(5, 10, Rounding::Down); assert_eq!(rational_1, (2u64).into());
492 assert_eq!(rational_2.into_perbill(), Perbill::from_float(0.5));
493 }
494
495 #[docify::export]
496 #[test]
497 fn fixed_u64_operation_example() {
498 let rational_1 = FixedU64::from_rational(10, 5); let rational_2 = FixedU64::from_rational(8, 5); let addition = rational_1 + rational_2;
502 let multiplication = rational_1 * rational_2;
503 let division = rational_1 / rational_2;
504 let subtraction = rational_1 - rational_2;
505
506 assert_eq!(addition, FixedU64::from_float(3.6));
507 assert_eq!(multiplication, FixedU64::from_float(3.2));
508 assert_eq!(division, FixedU64::from_float(1.25));
509 assert_eq!(subtraction, FixedU64::from_float(0.4));
510 }
511}
512
513#[cfg(test)]
514mod threshold_compare_tests {
515 use super::*;
516 use crate::traits::Saturating;
517 use core::cmp::Ordering;
518
519 #[test]
520 fn epsilon_ord_works() {
521 let b = 115u32;
522 let e = Perbill::from_percent(10).mul_ceil(b);
523
524 assert_eq!((103u32).tcmp(&b, e), Ordering::Equal);
526 assert_eq!((104u32).tcmp(&b, e), Ordering::Equal);
527 assert_eq!((115u32).tcmp(&b, e), Ordering::Equal);
528 assert_eq!((120u32).tcmp(&b, e), Ordering::Equal);
529 assert_eq!((126u32).tcmp(&b, e), Ordering::Equal);
530 assert_eq!((127u32).tcmp(&b, e), Ordering::Equal);
531
532 assert_eq!((128u32).tcmp(&b, e), Ordering::Greater);
533 assert_eq!((102u32).tcmp(&b, e), Ordering::Less);
534 }
535
536 #[test]
537 fn epsilon_ord_works_with_small_epc() {
538 let b = 115u32;
539 let e = Perbill::from_parts(100) * b;
541
542 assert_eq!((103u32).tcmp(&b, e), (103u32).cmp(&b));
544 assert_eq!((104u32).tcmp(&b, e), (104u32).cmp(&b));
545 assert_eq!((115u32).tcmp(&b, e), (115u32).cmp(&b));
546 assert_eq!((120u32).tcmp(&b, e), (120u32).cmp(&b));
547 assert_eq!((126u32).tcmp(&b, e), (126u32).cmp(&b));
548 assert_eq!((127u32).tcmp(&b, e), (127u32).cmp(&b));
549
550 assert_eq!((128u32).tcmp(&b, e), (128u32).cmp(&b));
551 assert_eq!((102u32).tcmp(&b, e), (102u32).cmp(&b));
552 }
553
554 #[test]
555 fn peru16_rational_does_not_overflow() {
556 let _ = PerU16::from_rational(17424870u32, 17424870);
559 }
560
561 #[test]
562 fn saturating_mul_works() {
563 assert_eq!(Saturating::saturating_mul(2, i32::MIN), i32::MIN);
564 assert_eq!(Saturating::saturating_mul(2, i32::MAX), i32::MAX);
565 }
566
567 #[test]
568 fn saturating_pow_works() {
569 assert_eq!(Saturating::saturating_pow(i32::MIN, 0), 1);
570 assert_eq!(Saturating::saturating_pow(i32::MAX, 0), 1);
571 assert_eq!(Saturating::saturating_pow(i32::MIN, 3), i32::MIN);
572 assert_eq!(Saturating::saturating_pow(i32::MIN, 2), i32::MAX);
573 assert_eq!(Saturating::saturating_pow(i32::MAX, 2), i32::MAX);
574 }
575}