1#![no_std]
2pub trait RoundedDiv<Rhs = Self> {
29 type Output;
31 fn rounded_div(self, rhs: Rhs) -> Self::Output;
33}
34
35macro_rules! aliases {
36 ($name:ident -> $data:ident) => {
37 impl RoundedDiv for $data {
38 type Output = Self;
39
40 #[inline]
41 fn rounded_div(self, rhs: $data) -> Self::Output {
42 $name(self, rhs)
43 }
44 }
45
46 pub use $name as $data;
47 };
48}
49
50macro_rules! unsigned_div_fn {
51 ($name:ident -> $data:ident) => {
52 #[inline]
54 pub const fn $name(dividend: $data, divisor: $data) -> $data {
55 let quotient = dividend / divisor;
56 let remainder = dividend % divisor;
57 quotient + (remainder << 1 >= divisor) as $data
58 }
59
60 aliases!($name -> $data);
61 };
62}
63
64macro_rules! signed_div_fn {
65 ($name:ident -> $data:ident do as $unsigned:ident) => {
66 pub const fn $name(dividend: $data, divisor: $data) -> $data {
68 const NEG_OF_MIN: $unsigned = $data::MIN as $unsigned;
73
74 const HALF_MIN: $data = $data::MIN / 2;
77 const HALF_MIN_PLUS_1: $data = HALF_MIN + 1;
78 const NEG_HALF_MIN: $data = -HALF_MIN;
79 const NEG_HALF_MIN_MINUS_1: $data = NEG_HALF_MIN - 1;
80 const HALF_MAX: $data = $data::MAX / 2;
81 const HALF_MAX_PLUS_1: $data = HALF_MAX + 1;
82 const NEG_HALF_MAX: $data = -HALF_MAX;
83 const NEG_HALF_MAX_MINUS_1: $data = NEG_HALF_MAX - 1;
84
85 match (dividend, divisor) {
86 ($data::MIN, -1) => panic!("attempt to divide with overflow"),
87 ($data::MIN, $data::MIN) | ($data::MAX, $data::MAX) => 1,
88 ($data::MIN, $data::MAX) | ($data::MAX, $data::MIN) => -1,
89
90 (0, ..=-1 | 1..) => 0,
91 (..=-1 | 1.., 1) => dividend,
92 (..=-1 | 1.., -1) => -dividend,
93
94 (_, 0) => panic!("attempt to divide by zero"),
95
96 ($data::MIN, 1..) => -(self::$unsigned(NEG_OF_MIN, divisor as $unsigned) as $data),
97 ($data::MIN, ..=-1) => self::$unsigned(NEG_OF_MIN, -divisor as $unsigned) as $data,
98
99 (HALF_MIN_PLUS_1..=NEG_HALF_MIN_MINUS_1, $data::MIN) => 0, (..=HALF_MIN, $data::MIN) => 1, (NEG_HALF_MIN.., $data::MIN) => -1, (NEG_HALF_MAX..=HALF_MAX, $data::MAX) => 0, (HALF_MAX_PLUS_1.., $data::MAX) => 1, (..=NEG_HALF_MAX_MINUS_1, $data::MAX) => -1, (1.., 1..) => self::$unsigned(dividend as $unsigned, divisor as $unsigned) as $data,
108 (..=-1, 1..) => -(self::$unsigned(-dividend as $unsigned, divisor as $unsigned) as $data),
109 (1.., ..=-1) => -(self::$unsigned(dividend as $unsigned, -divisor as $unsigned) as $data),
110 (..=-1, ..=-1) => self::$unsigned(-dividend as $unsigned, -divisor as $unsigned) as $data,
111 }
112 }
113
114 aliases!($name -> $data);
115 };
116}
117
118unsigned_div_fn!(rounded_div_u8 -> u8);
119unsigned_div_fn!(rounded_div_u16 -> u16);
120unsigned_div_fn!(rounded_div_u32 -> u32);
121unsigned_div_fn!(rounded_div_u64 -> u64);
122unsigned_div_fn!(rounded_div_u128 -> u128);
123unsigned_div_fn!(rounded_div_usize -> usize);
124
125signed_div_fn!(rounded_div_i8 -> i8 do as u8);
126signed_div_fn!(rounded_div_i16 -> i16 do as u16);
127signed_div_fn!(rounded_div_i32 -> i32 do as u32);
128signed_div_fn!(rounded_div_i64 -> i64 do as u64);
129signed_div_fn!(rounded_div_i128 -> i128 do as u128);
130signed_div_fn!(rounded_div_isize -> isize do as usize);