1use std::fmt;
2
3use num_traits::{
4 CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedSub, FromPrimitive, One, Signed,
5};
6
7pub trait Num:
9 num_traits::Num
10 + CheckedAdd
11 + CheckedMul
12 + CheckedSub
13 + CheckedNeg
14 + CheckedDiv
15 + Clone
16 + Ord
17 + FromPrimitive
18 + fmt::Debug
19 + fmt::Display
20{
21}
22
23impl<
24 T: num_traits::Num
25 + CheckedAdd
26 + CheckedMul
27 + CheckedSub
28 + CheckedNeg
29 + CheckedDiv
30 + Clone
31 + Ord
32 + FromPrimitive
33 + fmt::Debug
34 + fmt::Display,
35 > Num for T
36{
37}
38
39pub trait Unsigned: num_traits::Unsigned {
41 type Signed: TryFrom<Self> + UnsignedAbs<Unsigned = Self> + CheckedNeg;
43
44 fn to_signed(&self) -> crate::Result<Self::Signed>
46 where
47 Self: Clone,
48 {
49 self.clone().try_into().map_err(|_| crate::Error::Convert)
50 }
51
52 fn to_signed_with_sign(&self, negative: bool) -> crate::Result<Self::Signed>
54 where
55 Self: Clone,
56 Self::Signed: CheckedSub,
57 {
58 if negative {
59 self.to_opposite_signed()
60 } else {
61 self.to_signed()
62 }
63 }
64
65 fn to_opposite_signed(&self) -> crate::Result<Self::Signed>
67 where
68 Self: Clone,
69 Self::Signed: CheckedSub,
70 {
71 self.to_signed()?
72 .checked_neg()
73 .ok_or(crate::Error::Computation("to opposite signed"))
74 }
75
76 fn diff(self, other: Self) -> Self;
78
79 fn checked_signed_sub(self, other: Self) -> crate::Result<Self::Signed>
81 where
82 Self: Ord + Clone,
83 Self::Signed: CheckedSub,
84 {
85 if self >= other {
86 self.diff(other).to_signed()
87 } else {
88 self.diff(other).to_opposite_signed()
89 }
90 }
91
92 fn checked_add_with_signed(&self, other: &Self::Signed) -> Option<Self>
94 where
95 Self: CheckedAdd + CheckedSub,
96 {
97 let value = other.unsigned_abs();
98 if other.is_positive() {
99 self.checked_add(&value)
100 } else {
101 self.checked_sub(&value)
102 }
103 }
104
105 fn checked_sub_with_signed(&self, other: &Self::Signed) -> Option<Self>
107 where
108 Self: CheckedAdd + CheckedSub,
109 {
110 let value = other.unsigned_abs();
111 if other.is_positive() {
112 self.checked_sub(&value)
113 } else {
114 self.checked_add(&value)
115 }
116 }
117
118 fn checked_mul_with_signed(&self, other: &Self::Signed) -> Option<Self::Signed>
120 where
121 Self: CheckedMul,
122 {
123 let value = other.unsigned_abs();
124 if other.is_negative() {
125 Some(
126 Self::Signed::try_from(self.checked_mul(&value)?)
127 .ok()?
128 .checked_neg()?,
129 )
130 } else {
131 self.checked_mul(&value)?.try_into().ok()
132 }
133 }
134
135 fn as_divisor_to_round_up_magnitude_div(&self, dividend: &Self::Signed) -> Option<Self::Signed>
137 where
138 Self: Clone,
139 Self::Signed: CheckedSub + CheckedAdd + CheckedDiv,
140 {
141 if self.is_zero() {
142 return None;
143 }
144 let divisor: Self::Signed = self.clone().try_into().ok()?;
145 if dividend.is_negative() {
146 dividend
147 .checked_sub(&divisor)?
148 .checked_add(&One::one())?
149 .checked_div(&divisor)
150 } else {
151 dividend
152 .checked_add(&divisor)?
153 .checked_sub(&One::one())?
154 .checked_div(&divisor)
155 }
156 }
157
158 fn checked_round_up_div(&self, divisor: &Self) -> Option<Self>
160 where
161 Self: CheckedAdd + CheckedSub + Clone + CheckedDiv,
162 {
163 if divisor.is_zero() {
164 return None;
165 }
166 self.checked_add(divisor)?
167 .checked_sub(&One::one())?
168 .checked_div(divisor)
169 }
170
171 fn bound_magnitude(value: &Self::Signed, min: &Self, max: &Self) -> crate::Result<Self::Signed>
214 where
215 Self: Ord + Clone,
216 Self::Signed: Clone + CheckedSub,
217 {
218 if min > max {
219 return Err(crate::Error::InvalidArgument("min > max"));
220 }
221 let magnitude = value.unsigned_abs();
222 let negative = value.is_negative();
223 if magnitude < *min {
224 min.to_signed_with_sign(negative)
225 } else if magnitude > *max {
226 max.to_signed_with_sign(negative)
227 } else {
228 Ok(value.clone())
229 }
230 }
231}
232
233pub trait UnsignedAbs: Signed {
235 type Unsigned;
237
238 fn unsigned_abs(&self) -> Self::Unsigned;
240}
241
242pub trait MulDiv: Unsigned {
244 fn checked_mul_div(&self, numerator: &Self, denominator: &Self) -> Option<Self>;
248
249 fn checked_mul_div_ceil(&self, numerator: &Self, denominator: &Self) -> Option<Self>;
253
254 fn checked_mul_div_with_signed_numerator(
259 &self,
260 numerator: &Self::Signed,
261 denominator: &Self,
262 ) -> Option<Self::Signed> {
263 let ans = self
264 .checked_mul_div(&numerator.unsigned_abs(), denominator)?
265 .try_into()
266 .ok()?;
267 if numerator.is_positive() {
268 Some(ans)
269 } else {
270 ans.checked_neg()
271 }
272 }
273}
274
275impl Unsigned for u64 {
276 type Signed = i64;
277
278 fn diff(self, other: Self) -> Self {
279 self.abs_diff(other)
280 }
281}
282
283impl MulDiv for u64 {
284 #[allow(clippy::arithmetic_side_effects)]
285 fn checked_mul_div(&self, numerator: &Self, denominator: &Self) -> Option<Self> {
286 if *denominator == 0 {
287 return None;
288 }
289 let x = *self as u128;
290 let numerator = *numerator as u128;
291 let denominator = *denominator as u128;
292 let ans = x * numerator / denominator;
293 ans.try_into().ok()
294 }
295
296 #[allow(clippy::arithmetic_side_effects)]
297 fn checked_mul_div_ceil(&self, numerator: &Self, denominator: &Self) -> Option<Self> {
298 if *denominator == 0 {
299 return None;
300 }
301 let x = *self as u128;
302 let numerator = *numerator as u128;
303 let denominator = *denominator as u128;
304 let ans = (x * numerator).div_ceil(denominator);
305 ans.try_into().ok()
306 }
307}
308
309impl UnsignedAbs for i64 {
310 type Unsigned = u64;
311
312 fn unsigned_abs(&self) -> u64 {
313 (*self).unsigned_abs()
314 }
315}
316
317#[cfg(feature = "u128")]
318mod u128 {
320 use super::{MulDiv, Unsigned, UnsignedAbs};
321 use ruint::aliases::U256;
322
323 impl Unsigned for u128 {
324 type Signed = i128;
325
326 fn diff(self, other: Self) -> Self {
327 self.abs_diff(other)
328 }
329 }
330
331 impl UnsignedAbs for i128 {
332 type Unsigned = u128;
333
334 fn unsigned_abs(&self) -> u128 {
335 (*self).unsigned_abs()
336 }
337 }
338
339 impl MulDiv for u128 {
340 #[allow(clippy::arithmetic_side_effects)]
341 fn checked_mul_div(&self, numerator: &Self, denominator: &Self) -> Option<Self> {
342 if *denominator == 0 {
343 return None;
344 }
345 let x = U256::from(*self);
346 let numerator = U256::from(*numerator);
347 let denominator = U256::from(*denominator);
348 let ans = x * numerator / denominator;
349 ans.try_into().ok()
350 }
351
352 #[allow(clippy::arithmetic_side_effects)]
353 fn checked_mul_div_ceil(&self, numerator: &Self, denominator: &Self) -> Option<Self> {
354 if *denominator == 0 {
355 return None;
356 }
357 let x = U256::from(*self);
358 let numerator = U256::from(*numerator);
359 let denominator = U256::from(*denominator);
360 let ans = (x * numerator).div_ceil(denominator);
361 ans.try_into().ok()
362 }
363 }
364}
365
366#[cfg(test)]
367mod tests {
368 use super::*;
369
370 #[test]
371 fn round_up_magnitude_division() {
372 let b = 3u64;
373 let positive = 1i64;
374 let negative = -1i64;
375
376 assert_eq!(b.as_divisor_to_round_up_magnitude_div(&positive), Some(1));
377 assert_eq!(b.as_divisor_to_round_up_magnitude_div(&negative), Some(-1));
378 }
379
380 #[test]
381 fn round_up_division() {
382 let b = 3u64;
383 let a = 1u64;
384 assert_eq!(a.checked_round_up_div(&b), Some(1));
385 }
386
387 #[test]
388 fn mul_div_ceil() {
389 let a = 650_406_504u64;
390 let a2 = 650_406_505u64;
391 let b = 40_000_000_000u64;
392 let c = 80_000_000_000u64;
393 assert_eq!(a.checked_mul_div_ceil(&b, &c).unwrap(), 325_203_252);
394 assert_eq!(a2.checked_mul_div_ceil(&b, &c).unwrap(), 325_203_253);
395 }
396
397 #[cfg(feature = "u128")]
398 #[test]
399 fn mul_div_ceil_u128() {
400 let a = 650_406_504u128;
401 let a2 = 650_406_505u128;
402 let b = 40_000_000_000u128;
403 let c = 80_000_000_000u128;
404 assert_eq!(a.checked_mul_div_ceil(&b, &c).unwrap(), 325_203_252);
405 assert_eq!(a2.checked_mul_div_ceil(&b, &c).unwrap(), 325_203_253);
406 }
407
408 #[test]
409 fn bound_magnitude() {
410 let a = -123i64;
411 assert_eq!(Unsigned::bound_magnitude(&a, &0, &124u64).unwrap(), -123);
412 assert_eq!(Unsigned::bound_magnitude(&a, &0, &120u64).unwrap(), -120);
413 assert_eq!(Unsigned::bound_magnitude(&a, &124, &256u64).unwrap(), -124);
414 assert_eq!(Unsigned::bound_magnitude(&a, &125, &125u64).unwrap(), -125);
415
416 let b = 123i64;
417 assert_eq!(Unsigned::bound_magnitude(&b, &0, &124u64).unwrap(), 123);
418 assert_eq!(Unsigned::bound_magnitude(&b, &0, &120u64).unwrap(), 120);
419 assert_eq!(Unsigned::bound_magnitude(&b, &124, &256u64).unwrap(), 124);
420 assert_eq!(Unsigned::bound_magnitude(&b, &125, &125u64).unwrap(), 125);
421
422 let c = 0i64;
423 assert_eq!(Unsigned::bound_magnitude(&c, &1, &124u64).unwrap(), 1);
424
425 let d = -0i64;
426 assert_eq!(Unsigned::bound_magnitude(&d, &1, &124u64).unwrap(), 1);
427
428 let result = Unsigned::bound_magnitude(&0, &u64::MAX, &u64::MAX);
429 assert!(result.is_err());
430 }
431}