round_mult/
lib.rs

1#![doc = include_str!("../README.md")]
2#![no_std]
3#![deny(clippy::missing_inline_in_public_items, missing_docs)]
4#![cfg_attr(nightly, feature(portable_simd))]
5
6mod nzp;
7#[cfg(nightly)]
8pub use nzp::LanesMult;
9pub use nzp::NonZeroPow2;
10
11pub mod traits;
12use traits::Multiplier;
13
14/// Rounds the number down.
15#[inline(always)]
16pub fn down<M: Multiplier>(
17	value: M::Number, multiplier: M
18) -> M::Number {
19	multiplier.down(value)
20}
21
22/// Rounds the number up.
23///
24/// Returns [`None`] if the result overflows.
25#[inline(always)]
26pub fn up<M: Multiplier>(
27	value: M::Number, multiplier: M
28) -> Option<M::Number> {
29	multiplier.up(value)
30}
31
32#[cfg(test)]
33mod test {
34	use core::num::NonZeroU8;
35
36	use quickcheck::TestResult;
37	use quickcheck_macros::quickcheck;
38
39	use super::*;
40
41	#[quickcheck]
42	fn mult2_down_round_mult_is_identity(value: NonZeroPow2<u8>) -> bool {
43		down(value.get(), value) == value.get()
44	}
45
46	#[quickcheck]
47	fn mult2_up_round_mult_is_identity(value: NonZeroPow2<u8>) -> bool {
48		up(value.get(), value) == Some(value.get())
49	}
50
51	#[quickcheck]
52	fn mult_down_round_mult_is_identity(value: NonZeroU8) -> bool {
53		down(value.get(), value) == value.get()
54	}
55
56	#[quickcheck]
57	fn mult_up_round_mult_is_identity(value: NonZeroU8) -> bool {
58		up(value.get(), value) == Some(value.get())
59	}
60
61	#[quickcheck]
62	fn mult_up_overflow_is_none(value: u8, mult: NonZeroU8) -> TestResult {
63		if
64			value % mult.get() != 0 &&
65			u8::MAX - ((value / mult) * mult.get()) < mult.get()
66		{
67			TestResult::from_bool(up(value, mult).is_none())
68		} else {
69			TestResult::discard()
70		}
71	}
72
73	#[quickcheck]
74	fn mult2_up_overflow_is_none(
75		value: u8, mult: NonZeroPow2<u8>
76	) -> TestResult {
77		if
78			value % mult.get() != 0 &&
79			u8::MAX - ((value / mult.get()) * mult.get()) < mult.get()
80		{
81			TestResult::from_bool(up(value, mult).is_none())
82		} else {
83			TestResult::discard()
84		}
85	}
86
87	#[quickcheck]
88	fn mult2_down_is_correct(value: u8, mult: NonZeroPow2<u8>) -> bool {
89		down(value, mult) == (value / mult.get()) * mult.get()
90	}
91
92	#[quickcheck]
93	fn mult_down_is_correct(value: u8, mult: NonZeroU8) -> bool {
94		down(value, mult) == (value / mult.get()) * mult.get()
95	}
96
97	#[test]
98	fn up_12_4_identity() {
99		assert_eq!(
100			up(12_usize, NonZeroPow2::new(4).unwrap()).unwrap(),
101			12
102		);
103	}
104
105	#[test]
106	fn down_12_4() {
107		assert_eq!(
108			down(12_usize, NonZeroPow2::new(4).unwrap()),
109			12
110		);
111	}
112}