divrem-1.0.0/.cargo_vcs_info.json0000644000000001120000000000000123110ustar { "git": { "sha1": "d17f429aa2b47e6f4af5d8e5a0235418415b1741" } } divrem-1.0.0/.gitignore000064400000000000000000000005330000000000000130560ustar 00000000000000# Generated by Cargo # will have compiled files and executables /target/ # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk # Executable /src/main.rs divrem-1.0.0/Cargo.toml0000644000000015670000000000000103260ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "divrem" version = "1.0.0" authors = ["Letheed "] description = "Division and modulus variants" documentation = "https://docs.rs/divrem" readme = "README.md" keywords = ["division", "modulus", "no_std"] categories = ["mathematics", "no-std"] license = "MIT" repository = "https://github.com/letheed/divrem" divrem-1.0.0/Cargo.toml.orig000064400000000000000000000005520000000000000137560ustar 00000000000000[package] name = "divrem" version = "1.0.0" authors = ["Letheed "] description = "Division and modulus variants" documentation = "https://docs.rs/divrem" repository = "https://github.com/letheed/divrem" readme = "README.md" keywords = ["division", "modulus", "no_std"] categories = ["mathematics", "no-std"] license = "MIT" edition = "2018" divrem-1.0.0/LICENSE000064400000000000000000000020500000000000000120670ustar 00000000000000MIT License Copyright (c) 2018 Letheed Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. divrem-1.0.0/README.md000064400000000000000000000006340000000000000123470ustar 00000000000000# DivRem [Documentation][docs-rs] Rust library providing division and modulus variants: * Floored division and remainder. * Ceiled division and remainder. * Euclidian division and remaider. For every definition, we provide a `Div`, a `Rem` and a `DivRem` trait. A `DivRem` variant of `std`’s truncated division is also provided for convenience. This crate is `no_std`. [docs-rs]: https://docs.rs/divrem divrem-1.0.0/benches/lib.rs000064400000000000000000000146650000000000000136240ustar 00000000000000#![warn(rust_2018_idioms)] #![warn(clippy::pedantic)] #![warn(clippy::cargo)] #![warn(clippy::nursery)] #![allow(clippy::missing_const_for_fn)] #![feature(test)] extern crate test; use divrem::DivRem; use divrem::{DivCeil, DivRemCeil, RemCeil}; use divrem::{DivEuclid, DivRemEuclid, RemEuclid}; use divrem::{DivFloor, DivRemFloor, RemFloor}; use test::Bencher; #[inline] fn div_floor1(self_: i32, other: i32) -> i32 { DivFloor::div_floor(self_, other) } #[inline] fn div_floor2(self_: i32, other: i32) -> i32 { match DivRem::div_rem(self_, other) { (q, r) if (r > 0 && other < 0) || (r < 0 && other > 0) => q - 1, (q, _) => q, } } #[inline] fn div_floor3(self_: i32, other: i32) -> i32 { match DivRem::div_rem(self_, other) { (q, r) if r.signum() == -other.signum() => q - 1, (q, _) => q, } } #[inline] fn rem_floor1(self_: i32, other: i32) -> i32 { RemFloor::rem_floor(self_, other) } #[inline] fn rem_floor2(self_: i32, other: i32) -> i32 { let r = self_ % other; if (r > 0 && other < 0) || (r < 0 && other > 0) { r + other } else { r } } #[inline] fn rem_floor3(self_: i32, other: i32) -> i32 { let r = self_ % other; if r.signum() == -other.signum() { r + other } else { r } } #[inline] fn div_rem_floor1(self_: i32, other: i32) -> (i32, i32) { DivRemFloor::div_rem_floor(self_, other) } #[inline] fn div_rem_floor2(self_: i32, other: i32) -> (i32, i32) { match DivRem::div_rem(self_, other) { (q, r) if (r > 0 && other < 0) || (r < 0 && other > 0) => (q - 1, r + other), (q, r) => (q, r), } } #[inline] fn div_rem_floor3(self_: i32, other: i32) -> (i32, i32) { match DivRem::div_rem(self_, other) { (q, r) if r.signum() == -other.signum() => (q - 1, r + other), (q, r) => (q, r), } } #[inline] fn div_ceil1(self_: i32, other: i32) -> i32 { DivCeil::div_ceil(self_, other) } #[inline] fn div_ceil2(self_: i32, other: i32) -> i32 { match DivRem::div_rem(self_, other) { (q, r) if (r > 0 && other > 0) || (r < 0 && other < 0) => q + 1, (q, _) => q, } } #[inline] fn div_ceil3(self_: i32, other: i32) -> i32 { match DivRem::div_rem(self_, other) { (q, r) if r.signum() == other.signum() => q + 1, (q, _) => q, } } #[inline] fn rem_ceil1(self_: i32, other: i32) -> i32 { RemCeil::rem_ceil(self_, other) } #[inline] fn rem_ceil2(self_: i32, other: i32) -> i32 { let r = self_ % other; if (r > 0 && other > 0) || (r < 0 && other < 0) { r - other } else { r } } #[inline] fn rem_ceil3(self_: i32, other: i32) -> i32 { let r = self_ % other; if r.signum() == other.signum() { r - other } else { r } } #[inline] fn div_rem_ceil1(self_: i32, other: i32) -> (i32, i32) { DivRemCeil::div_rem_ceil(self_, other) } #[inline] fn div_rem_ceil2(self_: i32, other: i32) -> (i32, i32) { match DivRem::div_rem(self_, other) { (q, r) if (r > 0 && other > 0) || (r < 0 && other < 0) => (q + 1, r - other), (q, r) => (q, r), } } #[inline] fn div_rem_ceil3(self_: i32, other: i32) -> (i32, i32) { match DivRem::div_rem(self_, other) { (q, r) if r.signum() == other.signum() => (q + 1, r - other), (q, r) => (q, r), } } #[inline] fn div_euclid1(self_: i32, other: i32) -> i32 { DivEuclid::div_euclid(self_, other) } #[inline] fn rem_euclid1(self_: i32, other: i32) -> i32 { RemEuclid::rem_euclid(self_, other) } #[inline] fn div_rem_euclid1(self_: i32, other: i32) -> (i32, i32) { DivRemEuclid::div_rem_euclid(self_, other) } macro_rules! bench_loop_inner { ($function:expr) => {{ let mut sum = 0; for x in 0..1024 { for y in 1..x + 4 { sum += $function(x, y); sum += $function(x, -y); sum += $function(-x, y); sum += $function(-x, -y); } } sum }}; } macro_rules! bench_loop { ($function:expr,1) => { bench_loop_inner!($function) }; ($function:expr,2) => { bench_loop_inner!(|x, y| { let (q, r) = $function(x, y); q + r }) }; } macro_rules! bench { ($bench_name:ident, $function:ident, $n:tt) => { #[bench] fn $bench_name(b: &mut Bencher) { b.iter(|| bench_loop!($function, $n)); } }; } bench!(bench_div_floor1, div_floor1, 1); bench!(bench_div_floor2, div_floor2, 1); bench!(bench_div_floor3, div_floor3, 1); bench!(bench_rem_floor1, rem_floor1, 1); bench!(bench_rem_floor2, rem_floor2, 1); bench!(bench_rem_floor3, rem_floor3, 1); bench!(bench_div_rem_floor1, div_rem_floor1, 2); bench!(bench_div_rem_floor2, div_rem_floor2, 2); bench!(bench_div_rem_floor3, div_rem_floor3, 2); bench!(bench_div_ceil1, div_ceil1, 1); bench!(bench_div_ceil2, div_ceil2, 1); bench!(bench_div_ceil3, div_ceil3, 1); bench!(bench_rem_ceil1, rem_ceil1, 1); bench!(bench_rem_ceil2, rem_ceil2, 1); bench!(bench_rem_ceil3, rem_ceil3, 1); bench!(bench_div_rem_ceil1, div_rem_ceil1, 2); bench!(bench_div_rem_ceil2, div_rem_ceil2, 2); bench!(bench_div_rem_ceil3, div_rem_ceil3, 2); bench!(bench_div_euclid1, div_euclid1, 1); bench!(bench_rem_euclid1, rem_euclid1, 1); bench!(bench_div_rem_euclid1, div_rem_euclid1, 2); macro_rules! test_algos_eq { ($test_name:ident, $functions:expr) => { #[test] fn $test_name() { let mut table = Vec::new(); for f in &$functions { let mut results = Vec::new(); for x in 0..32 { for y in 1..x + 4 { results.push(f(x, y)); results.push(f(x, -y)); results.push(f(-x, y)); results.push(f(-x, -y)); } } table.push(results); } assert!(table.iter().zip(table.iter().skip(1)).all(|(a, b)| a == b)); } }; } test_algos_eq!(test_algos_eq_div_floor, [div_floor1, div_floor2, div_floor3]); test_algos_eq!(test_algos_eq_rem_floor, [rem_floor1, rem_floor2, rem_floor3]); test_algos_eq!(test_algos_eq_div_rem_floor, [div_rem_floor1, div_rem_floor2, div_rem_floor3]); test_algos_eq!(test_algos_eq_div_ceil, [div_ceil1, div_ceil2, div_ceil3]); test_algos_eq!(test_algos_eq_rem_ceil, [rem_ceil1, rem_ceil2, rem_ceil3]); test_algos_eq!(test_algos_eq_div_rem_ceil, [div_rem_ceil1, div_rem_ceil2, div_rem_ceil3]); divrem-1.0.0/rust-toolchain000064400000000000000000000000070000000000000137600ustar 00000000000000stable divrem-1.0.0/rustfmt.toml000064400000000000000000000032400000000000000134650ustar 00000000000000max_width = 100 hard_tabs = false tab_spaces = 4 newline_style = "Unix" use_small_heuristics = "Max" indent_style = "Block" wrap_comments = false format_code_in_doc_comments = true comment_width = 80 normalize_comments = true normalize_doc_attributes = true format_strings = false format_macro_matchers = true format_macro_bodies = true empty_item_single_line = true struct_lit_single_line = true fn_single_line = false where_single_line = true imports_indent = "Block" imports_layout = "Mixed" imports_granularity = "Module" group_imports = "StdExternalCrate" reorder_imports = true reorder_modules = true reorder_impl_items = true type_punctuation_density = "Wide" space_before_colon = false space_after_colon = true spaces_around_ranges = false binop_separator = "Front" remove_nested_parens = true combine_control_expr = true overflow_delimited_expr = false struct_field_align_threshold = 0 enum_discrim_align_threshold = 0 match_arm_blocks = true match_arm_leading_pipes = "Never" force_multiline_blocks = false fn_args_layout = "Tall" brace_style = "SameLineWhere" control_brace_style = "AlwaysSameLine" trailing_semicolon = true trailing_comma = "Vertical" match_block_trailing_comma = false blank_lines_upper_bound = 1 blank_lines_lower_bound = 0 inline_attribute_width = 0 merge_derives = true use_try_shorthand = true use_field_init_shorthand = true force_explicit_abi = true condense_wildcard_suffixes = true color = "Auto" unstable_features = true disable_all_formatting = false skip_children = false hide_parse_errors = false error_on_line_overflow = false error_on_unformatted = false report_todo = "Never" report_fixme = "Never" ignore = [] emit_mode = "Files" make_backup = false divrem-1.0.0/src/ceil.rs000064400000000000000000000146600000000000000131450ustar 00000000000000mod div { mod signed { use core::num::Wrapping; use core::ops::Div; use crate::DivCeil; macro_rules! impl_div_ceil_signed { ($t:ty, $zero:expr, $one:expr) => { impl DivCeil for $t { #[inline] fn div_ceil(self, other: Self) -> Self { if self > $zero && other > $zero { ((self - $one) / other) + $one } else if self < $zero && other < $zero { ((self + $one) / other) + $one } else { self / other } } } impl_forward_ref_binop!(impl DivCeil<$t> for $t { div_ceil -> Div::Output }); }; ($($t:ty),*) => {$( impl_div_ceil_signed!($t, 0, 1); impl_div_ceil_signed!(Wrapping<$t>, Wrapping(0), Wrapping(1)); )*}; } impl_div_ceil_signed!(i8, i16, i32, i64, i128, isize); } mod unsigned { use core::num::Wrapping; use core::ops::Div; use crate::DivCeil; macro_rules! impl_div_ceil_unsigned { ($t:ty, $zero:expr, $one:expr) => { impl DivCeil for $t { #[inline] fn div_ceil(self, other: Self) -> Self { if self == $zero { self / other } else { ((self - $one) / other) + $one } } } impl_forward_ref_binop!(impl DivCeil<$t> for $t { div_ceil -> Div::Output }); }; ($($t:ty),*) => {$( impl_div_ceil_unsigned!($t, 0, 1); impl_div_ceil_unsigned!(Wrapping<$t>, Wrapping(0), Wrapping(1)); )*}; } impl_div_ceil_unsigned!(u8, u16, u32, u64, u128, usize); } } mod rem { mod signed { use core::num::Wrapping; use core::ops::Rem; use crate::RemCeil; macro_rules! impl_rem_ceil_signed { ($t:ty, $zero:expr, $one:expr) => { impl RemCeil for $t { #[inline] fn rem_ceil(self, other: Self) -> Self { if self > $zero && other > $zero { ((self - $one) % other) - other + $one } else if self < $zero && other < $zero { ((self + $one) % other) - other - $one } else { self % other } } } impl_forward_ref_binop!(impl RemCeil<$t> for $t { rem_ceil -> Rem::Output }); }; ($($t:ty),*) => {$( impl_rem_ceil_signed!($t, 0, 1); impl_rem_ceil_signed!(Wrapping<$t>, Wrapping(0), Wrapping(1)); )*}; } impl_rem_ceil_signed!(i8, i16, i32, i64, i128, isize); } mod unsigned { use core::num::Wrapping; use core::ops::Rem; use crate::RemCeil; macro_rules! impl_rem_ceil_unsigned { ($t:ty, $zero:expr, $one:expr) => { impl RemCeil for $t { #[inline] fn rem_ceil(self, other: Self) -> Self { if self == $zero { self % other } else { ((self - $one) % other) - other + $one } } } impl_forward_ref_binop!(impl RemCeil<$t> for $t { rem_ceil -> Rem::Output }); }; ($($t:ty),*) => {$( // Modulus is negative or zero since divisor is positive. // impl_rem_ceil_unsigned!($t, 0, 1); impl_rem_ceil_unsigned!(Wrapping<$t>, Wrapping(0), Wrapping(1)); )*}; } impl_rem_ceil_unsigned!(u8, u16, u32, u64, u128, usize); } } mod divrem { mod signed { use core::num::Wrapping; use crate::{DivRem, DivRemCeil}; macro_rules! impl_div_rem_ceil_signed { ($t:ty, $zero:expr, $one:expr) => { impl DivRemCeil for $t { #[inline] fn div_rem_ceil(self, other: Self) -> (Self, Self) { if self > $zero && other > $zero { let (q, r) = (self - $one).div_rem(other); (q + $one, r - other + $one) } else if self < $zero && other < $zero { let (q, r) = (self + $one).div_rem(other); (q + $one, r - other - $one) } else { self.div_rem(other) } } } impl_forward_ref_binop!(impl DivRemCeil<$t> for $t { div_rem_ceil -> DivRem::Output }); }; ($($t:ty),*) => {$( impl_div_rem_ceil_signed!($t, 0, 1); impl_div_rem_ceil_signed!(Wrapping<$t>, Wrapping(0), Wrapping(1)); )*}; } impl_div_rem_ceil_signed!(i8, i16, i32, i64, i128, isize); } mod unsigned { use core::num::Wrapping; use crate::{DivRem, DivRemCeil}; macro_rules! impl_div_rem_ceil_unsigned { ($t:ty, $zero:expr, $one:expr) => { impl DivRemCeil for $t { #[inline] fn div_rem_ceil(self, other: Self) -> (Self, Self) { if self == $zero { self.div_rem(other) } else { let (q, r) = (self - $one).div_rem(other); (q + $one, r - other + $one) } } } impl_forward_ref_binop!(impl DivRemCeil<$t> for $t { div_rem_ceil -> DivRem::Output }); }; ($($t:ty),*) => {$( // Modulus is negative or zero since divisor is positive. // impl_div_rem_ceil_unsigned!($t, 0, 1); impl_div_rem_ceil_unsigned!(Wrapping<$t>, Wrapping(0), Wrapping(1)); )*}; } impl_div_rem_ceil_unsigned!(u8, u16, u32, u64, u128, usize); } } divrem-1.0.0/src/euclid.rs000064400000000000000000000132240000000000000134710ustar 00000000000000mod div { mod signed { use core::num::Wrapping; use core::ops::Div; use crate::{DivEuclid, DivRem}; macro_rules! impl_div_euclid_signed { ($t:ty, $zero:expr, $one:expr) => { impl DivEuclid for $t { #[inline] fn div_euclid(self, other: Self) -> Self { let (q, r) = self.div_rem(other); if r < $zero { if other > $zero { q - $one } else { q + $one } } else { q } } } impl_forward_ref_binop!(impl DivEuclid<$t> for $t { div_euclid -> Div::Output }); }; ($($t:ty),*) => {$( impl_div_euclid_signed!($t, 0, 1); impl_div_euclid_signed!(Wrapping<$t>, Wrapping(0), Wrapping(1)); )*}; } impl_div_euclid_signed!(i8, i16, i32, i64, i128, isize); } mod unsigned { use core::num::Wrapping; use core::ops::Div; use crate::DivEuclid; macro_rules! impl_div_euclid_unsigned { ($t:ty) => { impl DivEuclid for $t { #[inline] fn div_euclid(self, other: Self) -> Self { self / other } } impl_forward_ref_binop!(impl DivEuclid<$t> for $t { div_euclid -> Div::Output }); }; ($($t:ty),*) => {$( impl_div_euclid_unsigned!($t); impl_div_euclid_unsigned!(Wrapping<$t>); )*}; } impl_div_euclid_unsigned!(u8, u16, u32, u64, u128, usize); } } mod rem { mod signed { use core::num::Wrapping; use core::ops::Rem; use crate::RemEuclid; macro_rules! impl_rem_euclid_signed { ($t:ty, $zero:expr, $one:expr) => { impl RemEuclid for $t { #[inline] fn rem_euclid(self, other: Self) -> Self { let r = self % other; if r < $zero { if other > $zero { r + other } else { r - other } } else { r } } } impl_forward_ref_binop!(impl RemEuclid<$t> for $t { rem_euclid -> Rem::Output }); }; ($($t:ty),*) => {$( impl_rem_euclid_signed!($t, 0, 1); impl_rem_euclid_signed!(Wrapping<$t>, Wrapping(0), Wrapping(1)); )*}; } impl_rem_euclid_signed!(i8, i16, i32, i64, i128, isize); } mod unsigned { use core::num::Wrapping; use core::ops::Rem; use crate::RemEuclid; macro_rules! impl_rem_euclid_unsigned { ($t:ty) => { impl RemEuclid for $t { #[inline] fn rem_euclid(self, other: Self) -> Self { self % other } } impl_forward_ref_binop!(impl RemEuclid<$t> for $t { rem_euclid -> Rem::Output }); }; ($($t:ty),*) => {$( impl_rem_euclid_unsigned!($t); impl_rem_euclid_unsigned!(Wrapping<$t>); )*}; } impl_rem_euclid_unsigned!(u8, u16, u32, u64, u128, usize); } } mod divrem { mod signed { use core::num::Wrapping; use crate::{DivRem, DivRemEuclid}; macro_rules! impl_div_rem_euclid_signed { ($t:ty, $zero:expr, $one:expr) => { impl DivRemEuclid for $t { #[inline] fn div_rem_euclid(self, other: Self) -> (Self, Self) { let (q, r) = self.div_rem(other); if r < $zero { if other > $zero { (q - $one, r + other) } else { (q + $one, r - other) } } else { (q, r) } } } impl_forward_ref_binop!(impl DivRemEuclid<$t> for $t { div_rem_euclid -> DivRem::Output }); }; ($($t:ty),*) => {$( impl_div_rem_euclid_signed!($t, 0, 1); impl_div_rem_euclid_signed!(Wrapping<$t>, Wrapping(0), Wrapping(1)); )*}; } impl_div_rem_euclid_signed!(i8, i16, i32, i64, i128, isize); } mod unsigned { use core::num::Wrapping; use crate::{DivRem, DivRemEuclid}; macro_rules! impl_div_rem_euclid_unsigned { ($t:ty) => { impl DivRemEuclid for $t { #[inline] fn div_rem_euclid(self, other: Self) -> (Self, Self) { self.div_rem(other) } } impl_forward_ref_binop!(impl DivRemEuclid<$t> for $t { div_rem_euclid -> DivRem::Output }); }; ($($t:ty),*) => {$( impl_div_rem_euclid_unsigned!($t); impl_div_rem_euclid_unsigned!(Wrapping<$t>); )*}; } impl_div_rem_euclid_unsigned!(u8, u16, u32, u64, u128, usize); } } divrem-1.0.0/src/floor.rs000064400000000000000000000131530000000000000133460ustar 00000000000000mod div { mod signed { use core::num::Wrapping; use core::ops::Div; use crate::DivFloor; macro_rules! impl_div_floor_signed { ($t:ty, $zero:expr, $one:expr) => { impl DivFloor for $t { #[inline] fn div_floor(self, other: Self) -> Self { if self > $zero && other < $zero { ((self - $one) / other) - $one } else if self < $zero && other > $zero { ((self + $one) / other) - $one } else { self / other } } } impl_forward_ref_binop!(impl DivFloor<$t> for $t { div_floor -> Div::Output }); }; ($($t:ty),*) => {$( impl_div_floor_signed!($t, 0, 1); impl_div_floor_signed!(Wrapping<$t>, Wrapping(0), Wrapping(1)); )*}; } impl_div_floor_signed!(i8, i16, i32, i64, i128, isize); } mod unsigned { use core::num::Wrapping; use core::ops::Div; use crate::DivFloor; macro_rules! impl_div_floor_unsigned { ($t:ty) => { impl DivFloor for $t { #[inline] fn div_floor(self, other: Self) -> Self { self / other } } impl_forward_ref_binop!(impl DivFloor<$t> for $t { div_floor -> Div::Output }); }; ($($t:ty),*) => {$( impl_div_floor_unsigned!($t); impl_div_floor_unsigned!(Wrapping<$t>); )*}; } impl_div_floor_unsigned!(u8, u16, u32, u64, u128, usize); } } mod rem { mod signed { use core::num::Wrapping; use core::ops::Rem; use crate::RemFloor; macro_rules! impl_rem_floor_signed { ($t:ty, $zero:expr, $one:expr) => { impl RemFloor for $t { #[inline] fn rem_floor(self, other: Self) -> Self { if self > $zero && other < $zero { ((self - $one) % other) + other + $one } else if self < $zero && other > $zero { ((self + $one) % other) + other - $one } else { self % other } } } impl_forward_ref_binop!(impl RemFloor<$t> for $t { rem_floor -> Rem::Output }); }; ($($t:ty),*) => {$( impl_rem_floor_signed!($t, 0, 1); impl_rem_floor_signed!(Wrapping<$t>, Wrapping(0), Wrapping(1)); )*}; } impl_rem_floor_signed!(i8, i16, i32, i64, i128, isize); } mod unsigned { use core::num::Wrapping; use core::ops::Rem; use crate::RemFloor; macro_rules! impl_rem_floor_unsigned { ($t:ty) => { impl RemFloor for $t { #[inline] fn rem_floor(self, other: Self) -> Self { self % other } } impl_forward_ref_binop!(impl RemFloor<$t> for $t { rem_floor -> Rem::Output }); }; ($($t:ty),*) => {$( impl_rem_floor_unsigned!($t); impl_rem_floor_unsigned!(Wrapping<$t>); )*}; } impl_rem_floor_unsigned!(u8, u16, u32, u64, u128, usize); } } mod divrem { mod signed { use core::num::Wrapping; use crate::{DivRem, DivRemFloor}; macro_rules! impl_div_rem_floor_signed { ($t:ty, $zero:expr, $one:expr) => { impl DivRemFloor for $t { #[inline] fn div_rem_floor(self, other: Self) -> (Self, Self) { if self > $zero && other < $zero { let (q, r) = (self - $one).div_rem(other); (q - $one, r + other + $one) } else if self < $zero && other > $zero { let (q, r) = (self + $one).div_rem(other); (q - $one, r + other - $one) } else { self.div_rem(other) } } } impl_forward_ref_binop!(impl DivRemFloor<$t> for $t { div_rem_floor -> DivRem::Output }); }; ($($t:ty),*) => {$( impl_div_rem_floor_signed!($t, 0, 1); impl_div_rem_floor_signed!(Wrapping<$t>, Wrapping(0), Wrapping(1)); )*}; } impl_div_rem_floor_signed!(i8, i16, i32, i64, i128, isize); } mod unsigned { use core::num::Wrapping; use crate::{DivRem, DivRemFloor}; macro_rules! impl_div_rem_floor_unsigned { ($t:ty) => { impl DivRemFloor for $t { #[inline] fn div_rem_floor(self, other: Self) -> (Self, Self) { self.div_rem(other) } } impl_forward_ref_binop!(impl DivRemFloor<$t> for $t { div_rem_floor -> DivRem::Output }); }; ($($t:ty),*) => {$( impl_div_rem_floor_unsigned!($t); impl_div_rem_floor_unsigned!(Wrapping<$t>); )*}; } impl_div_rem_floor_unsigned!(u8, u16, u32, u64, u128, usize); } } divrem-1.0.0/src/lib.rs000064400000000000000000000107210000000000000127710ustar 00000000000000//! Division and modulus traits and implementations. //! //! There are several definitions for the division and modulus //! functions, each with different properties. //! Probably the most common in computer science is truncated division //! (rounding towards zero) since it is the one provided by most processors //! and defined as the `/` (and matching `%`) operator in the ISO C99 standard. //! //! This crate provides the following definitions: //! //! * Floored division (rounding towards negative infinity). //! * Ceiled division (rounding towards positive infinity). //! * Euclidean division (sign of modulus is always positive). //! //! For every definition, we provide a `Div`, a `Rem` and a `DivRem` variant. //! //! A `DivRem` variant of the truncated division is also provided for //! convenience since it does not exist in the standard library. #![warn(missing_docs)] #![warn(rust_2018_idioms)] #![warn(clippy::pedantic)] #![warn(clippy::cargo)] #![warn(clippy::nursery)] #![deny(unsafe_code)] #![no_std] use core::ops::{Div, Rem}; /// Truncated division and remainder. /// /// Truncates the quotient and effectively rounds towards zero. /// The sign of the modulus is always the same as the sign of the dividend. /// /// This is the same as the `/` and `%` operators. /// /// This is equivalent to the `quotRem` function in Haskell. pub trait DivRem: Div + Rem { /// The resulting type after applying the `/` and `%` operators. type Output; /// Performs the `/` and `%` operations. fn div_rem(self, other: RHS) -> >::Output; } /// Floored division. /// /// Floors the quotient and effectively rounds towards negative infinity. /// /// This is equivalent to the `div` function in Haskell. pub trait DivFloor: Div { /// Performs the floored division operation. fn div_floor(self, other: RHS) -> >::Output; } /// Floored division remainder. /// /// The sign of the modulus is always the same as the sign of the divisor /// or zero. /// /// This is equivalent to the `mod` function in Haskell. pub trait RemFloor: Rem { /// Returns the remainder of the floored division operation. fn rem_floor(self, other: RHS) -> >::Output; } /// Floored division and remainder. /// /// Floors the quotient and effectively rounds towards negative infinity. /// The sign of the modulus is always the same as the sign of the divisor /// or zero. /// /// This is equivalent to the `divMod` function in Haskell. pub trait DivRemFloor: DivRem { /// Performs the floored division operation with remainder. fn div_rem_floor(self, other: RHS) -> >::Output; } /// Euclidean division. /// /// The sign of the modulus is always positive or zero. pub trait DivEuclid: Div { /// Performs the euclidean division operation. fn div_euclid(self, other: RHS) -> >::Output; } /// Euclidean remainder. /// /// The sign of the modulus is always positive or zero. pub trait RemEuclid: Rem { /// Returns the remainder of the euclidean division operation. fn rem_euclid(self, other: RHS) -> >::Output; } /// Euclidean division and remainder. /// /// The sign of the modulus is always positive or zero. pub trait DivRemEuclid: DivRem { /// Performs the euclidean division operation with remainder. fn div_rem_euclid(self, other: RHS) -> >::Output; } /// Ceiled division. /// /// Ceils the quotient and effectively rounds towards positive infinity. pub trait DivCeil: Div { /// Performs the ceiled division operation. fn div_ceil(self, other: RHS) -> >::Output; } /// Ceiled division remainder. /// /// The sign of the modulus is always the opposite of the sign of the divisor /// or zero. pub trait RemCeil: Rem { /// Returns the remainder of the ceiled division operation. fn rem_ceil(self, other: RHS) -> >::Output; } /// Ceiled division and remainder. /// /// Ceils the quotient and effectively rounds towards positive infinity. /// The sign of the modulus is always the opposite of the sign of the divisor /// or zero. pub trait DivRemCeil: DivRem { /// Performs the ceiled division operation with remainder. fn div_rem_ceil(self, other: RHS) -> >::Output; } #[macro_use] mod macros; mod ceil; mod euclid; mod floor; mod trunc; divrem-1.0.0/src/macros.rs000064400000000000000000000031730000000000000135120ustar 00000000000000macro_rules! impl_forward_ref_binop { (impl $trait:ident < $u:ty > for $t:ty { $method:ident -> $target:ident::Output }) => { impl<'a> $trait<$u> for &'a $t { #[inline] fn $method(self, other: $u) -> <$t as $target<$u>>::Output { $trait::$method(*self, other) } } impl<'a> $trait<&'a $u> for $t { #[inline] fn $method(self, other: &'a $u) -> <$t as $target<$u>>::Output { $trait::$method(self, *other) } } impl<'a, 'b> $trait<&'a $u> for &'b $t { #[inline] fn $method(self, other: &'a $u) -> <$t as $target<$u>>::Output { $trait::$method(*self, *other) } } }; (impl $trait:ident < $u:ty > for $t:ty { $method:ident -> Output }) => { impl<'a> $trait<$u> for &'a $t { type Output = <$t as $trait<$u>>::Output; #[inline] fn $method(self, other: $u) -> <$t as $trait<$u>>::Output { $trait::$method(*self, other) } } impl<'a> $trait<&'a $u> for $t { type Output = <$t as $trait<$u>>::Output; #[inline] fn $method(self, other: &'a $u) -> <$t as $trait<$u>>::Output { $trait::$method(self, *other) } } impl<'a, 'b> $trait<&'a $u> for &'b $t { type Output = <$t as $trait<$u>>::Output; #[inline] fn $method(self, other: &'a $u) -> <$t as $trait<$u>>::Output { $trait::$method(*self, *other) } } }; } divrem-1.0.0/src/trunc.rs000064400000000000000000000012700000000000000133550ustar 00000000000000use core::num::Wrapping; use core::ops::{Div, Rem}; use super::DivRem; macro_rules! impl_div_rem_trunc { ($t:ty) => { impl DivRem for $t { type Output = (::Output, ::Output); #[inline] fn div_rem(self, other: Self) -> ::Output { (self / other, self % other) } } impl_forward_ref_binop!(impl DivRem<$t> for $t { div_rem -> Output }); }; ($($t:ty),*) => {$( impl_div_rem_trunc!($t); impl_div_rem_trunc!(Wrapping<$t>); )*}; } impl_div_rem_trunc!(i8, i16, i32, i64, i128, isize); impl_div_rem_trunc!(u8, u16, u32, u64, u128, usize); divrem-1.0.0/tests/lib.rs000064400000000000000000000160730000000000000133520ustar 00000000000000#![warn(rust_2018_idioms)] #![warn(clippy::pedantic)] #![warn(clippy::cargo)] #![warn(clippy::nursery)] #![allow(clippy::missing_const_for_fn)] #![feature(concat_idents)] #[rustfmt::skip] const XY: [(i32, i32); 8] = [ (8, 3), (8, -3), (-8, 3), (-8, -3) , (1, 2), (1, -2), (-1, 2), (-1, -2) ]; #[rustfmt::skip] const QR_TRUNC: [(i32, i32); 8] = [ (2, 2), (-2, 2), (-2, -2), (2, -2) , (0, 1), (0, 1), (0, -1), (0, -1) ]; #[rustfmt::skip] const QR_FLOOR: [(i32, i32); 8] = [ (2, 2), (-3, -1), (-3, 1), (2, -2) , (0, 1), (-1, -1), (-1, 1), (0, -1) ]; #[rustfmt::skip] const QR_CEIL: [(i32, i32); 8] = [ (3, -1), (-2, 2), (-2, -2), (3, 1) , (1, -1), (0, 1), (0, -1), (1, 1) ]; #[rustfmt::skip] const QR_EUCLID: [(i32, i32); 8] = [ (2, 2), (-2, 2), (-3, 1), (3, 1) , (0, 1), (0, 1), (-1, 1), (1, 1) ]; macro_rules! div_rem_functions { ($($t:ty),*) => {$( fn div_rem(x: $t, y: $t) -> ($t, $t) { div_rem_trunc(x, y) } fn div_rem_trunc(x: $t, y: $t) -> ($t, $t) { let q = ((x as f32) / (y as f32)).trunc() as $t; let r = x - q * y; (q, r) } fn div_rem_floor(x: $t, y: $t) -> ($t, $t) { let q = ((x as f32) / (y as f32)).floor() as $t; let r = x - q * y; (q, r) } fn div_floor(x: $t, y: $t) -> $t { div_rem_floor(x, y).0 } fn rem_floor(x: $t, y: $t) -> $t { div_rem_floor(x, y).1 } fn div_euclid(x: $t, y: $t) -> $t { div_rem_euclid(x, y).0 } fn rem_euclid(x: $t, y: $t) -> $t { div_rem_euclid(x, y).1 } )*}; } mod signed { use divrem::DivRem; use divrem::{DivCeil, DivRemCeil, RemCeil}; use divrem::{DivEuclid, DivRemEuclid, RemEuclid}; use divrem::{DivFloor, DivRemFloor, RemFloor}; fn div_trunc(x: i32, y: i32) -> i32 { div_rem_trunc(x, y).0 } fn rem_trunc(x: i32, y: i32) -> i32 { div_rem_trunc(x, y).1 } fn div_rem_ceil(x: i32, y: i32) -> (i32, i32) { #[allow(clippy::cast_possible_truncation)] // ⌈x/y⌉ is an integer <= |x|. let q = (f64::from(x) / f64::from(y)).ceil() as i32; let r = x - q * y; (q, r) } fn div_ceil(x: i32, y: i32) -> i32 { div_rem_ceil(x, y).0 } fn rem_ceil(x: i32, y: i32) -> i32 { div_rem_ceil(x, y).1 } fn div_rem_euclid(x: i32, y: i32) -> (i32, i32) { let (mut q, mut r) = (x / y, x % y); // Euclid is mod dominant. // A unique solution exists for r>=0. if r < 0 { if y > 0 { q -= 1; r += y; } else { q += 1; r -= y; } } (q, r) } div_rem_functions!(i32); macro_rules! test_table { ($test_name:ident, $table:ident, $variant:ident) => { #[test] fn $test_name() { use super::{$table, XY}; for (&(x, y), &tqr) in XY.iter().zip(&$table) { let q = concat_idents!(div_, $variant)(x, y); let r = concat_idents!(rem_, $variant)(x, y); let qr = concat_idents!(div_rem_, $variant)(x, y); assert_eq!(tqr, (q, r)); assert_eq!(tqr, qr); } } }; } test_table!(test_table_trunc, QR_TRUNC, trunc); test_table!(test_table_floor, QR_FLOOR, floor); test_table!(test_table_ceil, QR_CEIL, ceil); test_table!(test_table_euclid, QR_EUCLID, euclid); macro_rules! test { ($test_name:ident, $trait:ident, $function:ident) => { #[test] fn $test_name() { for x in 0_i32..32 { for y in 1_i32..x + 4 { assert_eq!($trait::$function(x, y), $function(x, y)); assert_eq!($trait::$function(x, -y), $function(x, -y)); assert_eq!($trait::$function(-x, y), $function(-x, y)); assert_eq!($trait::$function(-x, -y), $function(-x, -y)); } } } }; } test!(test_div_rem_trunc, DivRem, div_rem); test!(test_div_floor, DivFloor, div_floor); test!(test_rem_floor, RemFloor, rem_floor); test!(test_div_rem_floor, DivRemFloor, div_rem_floor); test!(test_div_euclid, DivEuclid, div_euclid); test!(test_rem_euclid, RemEuclid, rem_euclid); test!(test_div_rem_euclid, DivRemEuclid, div_rem_euclid); test!(test_div_ceil, DivCeil, div_ceil); test!(test_rem_ceil, RemCeil, rem_ceil); test!(test_div_rem_ceil, DivRemCeil, div_rem_ceil); } mod unsigned { use std::num::Wrapping; use divrem::DivRem; use divrem::{DivCeil, DivRemCeil, RemCeil}; use divrem::{DivEuclid, DivRemEuclid, RemEuclid}; use divrem::{DivFloor, DivRemFloor, RemFloor}; fn div_ceil(x: u32, y: u32) -> u32 { #[allow(clippy::cast_sign_loss)] // ∀x,y>=0 ⌈x/y⌉>=0. #[allow(clippy::cast_possible_truncation)] // ⌈x/y⌉ is an integer <=x. let q = (f64::from(x) / f64::from(y)).ceil() as u32; q } fn div_rem_ceil(x: Wrapping, y: Wrapping) -> (Wrapping, Wrapping) { #[allow(clippy::cast_sign_loss)] // ∀n,m>=0 ⌈n/m⌉>=0 #[allow(clippy::cast_possible_truncation)] // ⌈x/y⌉ is an integer <=x. let q = Wrapping((f64::from(x.0) / f64::from(y.0)).ceil() as u32); let r = x - q * y; (q, r) } fn rem_ceil(x: Wrapping, y: Wrapping) -> Wrapping { div_rem_ceil(x, y).1 } fn div_rem_euclid(x: u32, y: u32) -> (u32, u32) { (x / y, x % y) } div_rem_functions!(u32); macro_rules! test { ($test_name:ident, $trait:ident, $function:ident) => { #[test] fn $test_name() { for x in 0_u32..32 { for y in 1_u32..x + 4 { assert_eq!($trait::$function(x, y), $function(x, y)); } } } }; } test!(test_div_rem_trunc, DivRem, div_rem); test!(test_div_floor, DivFloor, div_floor); test!(test_rem_floor, RemFloor, rem_floor); test!(test_div_rem_floor, DivRemFloor, div_rem_floor); test!(test_div_euclid, DivEuclid, div_euclid); test!(test_rem_euclid, RemEuclid, rem_euclid); test!(test_div_rem_euclid, DivRemEuclid, div_rem_euclid); test!(test_div_ceil, DivCeil, div_ceil); macro_rules! test_wrap { ($test_name:ident, $trait:ident, $function:ident) => { #[test] fn $test_name() { for x in 0_u32..32 { for y in 1_u32..x + 4 { let (x, y) = (Wrapping(x), Wrapping(y)); assert_eq!($trait::$function(x, y), $function(x, y)); } } } }; } test_wrap!(test_rem_ceil, RemCeil, rem_ceil); test_wrap!(test_div_rem_ceil, DivRemCeil, div_rem_ceil); }