#rounding #round #simd #data-processing #multiplier

no-std round_mult

A tiny library to round a number up or down to a multiplier

3 releases

0.1.3 Jul 19, 2023
0.1.2 Aug 24, 2022
0.1.1 Aug 19, 2022
0.1.0 Aug 12, 2022

#458 in Concurrency

28 downloads per month
Used in numscan

MIT/Apache

20KB
382 lines

round_mult

A tiny library to round a number up or down to a multiplier.

Usage

The library has two functions:

  • round_mult::[up]
  • round_mult::down

They both take a value and a multiplier and round the value down or up to the multiplier respectively.

Multiplier

There are two kind of multipliers:

  • NonZeroPow2 When the multiplier is a power of two, it can be calculated faster. Prefer it when possible.
  • std::num::NonZeroU_ for any multiplier value.

Example

E.g.

use std::num::NonZeroUsize;
use round_mult::NonZeroPow2;

assert_eq!(
	round_mult::down(70usize, NonZeroPow2::v32()),
	64
);

// These two are semantically equivalent:
assert_eq!(
	round_mult::down(70usize, NonZeroPow2::new(32).unwrap()),
	round_mult::down(70usize, NonZeroUsize::new(32).unwrap()),
);
// but NonZeroPow2 (the first parameter) is faster.

// However, it can't be used when the multiplier isn't a power of two.
// In that case use a NonZeroU_ type:
assert_eq!(
    round_mult::down(109usize, NonZeroUsize::new(10).unwrap()),
    100
);
assert_eq!(
    round_mult::up(101usize, NonZeroUsize::new(10).unwrap()),
    Some(110)
);

Example: SIMD

The main motivation for this library is SIMD processing. Specifically when the length of data isn't a multiple of the SIMD lanes count, which means you will have a remainder of data to process without SIMD.

use round_mult::NonZeroPow2;

fn f(data: &[u8]) {
	// for this example, assume we want to use u8x32 SIMD. We could do:
	// type Simd = std::simd::u8x32;
	// let lanes = NonZeroPow2::of::<Simd>();
	// but to keep this example compiling on stable, we could also use:
	let lanes = NonZeroPow2::v32();

	let mut i = 0;

	while i < round_mult::down(data.len(), lanes) {
		// SIMD process…
		// let data = Simd::from_slice(s[i..]);
		// etc. etc.
		i += lanes.get();
	}
	while i < data.len() {
		// remainder process…
		i += 1;
	}
}

No runtime deps

~10KB