From 68600a3def25fd102d07840edceb527ca7dca0ab Mon Sep 17 00:00:00 2001 From: Edoardo Morandi Date: Thu, 22 Feb 2018 01:57:58 +0100 Subject: [PATCH 1/3] Implementation of std::iter::{Product, Sum} This is relative to the [issue 4](https://github.com/rust-num/num-bigint/issues/4). This is a very simple implementation, based on two macros. Maybe a more elegant solution is possible for these, feel free to suggest. Two tests for both `BigInt` and `BigUInt` have been added, one relative to the `Sum`, the other to the `Product`. --- src/bigint.rs | 4 ++++ src/biguint.rs | 5 ++++- src/macros.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ src/tests/bigint.rs | 32 ++++++++++++++++++++++++++++++++ src/tests/biguint.rs | 33 +++++++++++++++++++++++++++++++++ 5 files changed, 115 insertions(+), 1 deletion(-) diff --git a/src/bigint.rs b/src/bigint.rs index 7c7c4dfa..b820ffca 100644 --- a/src/bigint.rs +++ b/src/bigint.rs @@ -6,6 +6,7 @@ use std::cmp::Ordering::{self, Less, Greater, Equal}; use std::{i64, u64}; #[allow(unused_imports)] use std::ascii::AsciiExt; +use std::iter::{Product, Sum}; #[cfg(feature = "serde")] use serde; @@ -1779,6 +1780,9 @@ impl BigInt { } } +impl_sum_iter_type!(BigInt); +impl_product_iter_type!(BigInt); + /// Perform in-place two's complement of the given binary representation, /// in little-endian byte order. #[inline] diff --git a/src/biguint.rs b/src/biguint.rs index eec6fda4..df60d586 100644 --- a/src/biguint.rs +++ b/src/biguint.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; use std::default::Default; -use std::iter::repeat; +use std::iter::{repeat, Product, Sum}; use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Rem, Shl, Shr, Sub, AddAssign, BitAndAssign, BitOrAssign, BitXorAssign, DivAssign, MulAssign, RemAssign, ShlAssign, ShrAssign, SubAssign}; @@ -1690,6 +1690,9 @@ pub fn trailing_zeros(u: &BigUint) -> Option { .map(|(i, digit)| i * big_digit::BITS + digit.trailing_zeros() as usize) } +impl_sum_iter_type!(BigUint); +impl_product_iter_type!(BigUint); + #[cfg(feature = "serde")] impl serde::Serialize for BigUint { fn serialize(&self, serializer: S) -> Result diff --git a/src/macros.rs b/src/macros.rs index 93433611..e359e4ae 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -314,3 +314,45 @@ macro_rules! promote_all_scalars { promote_signed_scalars!(impl $imp for $res, $method); } } + +macro_rules! impl_sum_iter_type { + ($res:ty) => { + impl Sum for $res { + impl_sum_iter_type!($res, $res); + } + + impl<'a> Sum<&'a $res> for $res { + impl_sum_iter_type!($res, &'a $res); + } + }; + + ($res:ty, $item:ty) => { + fn sum(iter: I) -> Self + where + I: Iterator + { + iter.fold(Zero::zero(), <$res>::add) + } + }; +} + +macro_rules! impl_product_iter_type { + ($res:ty) => { + impl Product for $res { + impl_product_iter_type!($res, $res); + } + + impl<'a> Product<&'a $res> for $res { + impl_product_iter_type!($res, &'a $res); + } + }; + + ($res:ty, $item:ty) => { + fn product(iter: I) -> Self + where + I: Iterator + { + iter.fold(One::one(), <$res>::mul) + } + }; +} diff --git a/src/tests/bigint.rs b/src/tests/bigint.rs index 1ff1d673..f2431951 100644 --- a/src/tests/bigint.rs +++ b/src/tests/bigint.rs @@ -1217,3 +1217,35 @@ fn test_random_shr() { } } } +#[test] +fn test_iter_sum() { + let result: BigInt = FromPrimitive::from_isize(-1234567).unwrap(); + let data: Vec = vec![ + FromPrimitive::from_i32(-1000000).unwrap(), + FromPrimitive::from_i32(-200000).unwrap(), + FromPrimitive::from_i32(-30000).unwrap(), + FromPrimitive::from_i32(-4000).unwrap(), + FromPrimitive::from_i32(-500).unwrap(), + FromPrimitive::from_i32(-60).unwrap(), + FromPrimitive::from_i32(-7).unwrap(), + ]; + + assert_eq!(result, data.iter().sum()); + assert_eq!(result, data.into_iter().sum()); +} + +#[test] +fn test_iter_product() { + let data: Vec = vec![ + FromPrimitive::from_i32(1001).unwrap(), + FromPrimitive::from_i32(-1002).unwrap(), + FromPrimitive::from_i32(1003).unwrap(), + FromPrimitive::from_i32(-1004).unwrap(), + FromPrimitive::from_i32(1005).unwrap(), + ]; + let result = data.get(0).unwrap() * data.get(1).unwrap() * data.get(2).unwrap() + * data.get(3).unwrap() * data.get(4).unwrap(); + + assert_eq!(result, data.iter().product()); + assert_eq!(result, data.into_iter().product()); +} diff --git a/src/tests/biguint.rs b/src/tests/biguint.rs index ddb68b1e..c62a8ad0 100644 --- a/src/tests/biguint.rs +++ b/src/tests/biguint.rs @@ -1676,3 +1676,36 @@ fn test_mul_divide_torture() { fn test_mul_divide_torture_long() { test_mul_divide_torture_count(1000000); } + +#[test] +fn test_iter_sum() { + let result: BigUint = FromPrimitive::from_isize(1234567).unwrap(); + let data: Vec = vec![ + FromPrimitive::from_u32(1000000).unwrap(), + FromPrimitive::from_u32(200000).unwrap(), + FromPrimitive::from_u32(30000).unwrap(), + FromPrimitive::from_u32(4000).unwrap(), + FromPrimitive::from_u32(500).unwrap(), + FromPrimitive::from_u32(60).unwrap(), + FromPrimitive::from_u32(7).unwrap(), + ]; + + assert_eq!(result, data.iter().sum()); + assert_eq!(result, data.into_iter().sum()); +} + +#[test] +fn test_iter_product() { + let data: Vec = vec![ + FromPrimitive::from_u32(1001).unwrap(), + FromPrimitive::from_u32(1002).unwrap(), + FromPrimitive::from_u32(1003).unwrap(), + FromPrimitive::from_u32(1004).unwrap(), + FromPrimitive::from_u32(1005).unwrap(), + ]; + let result = data.get(0).unwrap() * data.get(1).unwrap() * data.get(2).unwrap() + * data.get(3).unwrap() * data.get(4).unwrap(); + + assert_eq!(result, data.iter().product()); + assert_eq!(result, data.into_iter().product()); +} From d6fa4ac632c8d7abf18df1e6fad9cf49f8f03e35 Mon Sep 17 00:00:00 2001 From: Edoardo Morandi Date: Thu, 22 Feb 2018 10:17:22 +0100 Subject: [PATCH 2/3] Generic implementation for `Sum` and `Product` The succestion came from @cupiver, and it was simple and elegant. Now it should be possible to use `std::iter::{Sum, Product}` with everything that can be Add`-ed and `Mul`-tiplied _against_ `BigInt` and `BigUint` --- src/macros.rs | 42 ++++++++++++++++-------------------------- src/tests/bigint.rs | 20 ++++++++++++++++++++ src/tests/biguint.rs | 20 ++++++++++++++++++++ 3 files changed, 56 insertions(+), 26 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index e359e4ae..733af73a 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -317,42 +317,32 @@ macro_rules! promote_all_scalars { macro_rules! impl_sum_iter_type { ($res:ty) => { - impl Sum for $res { - impl_sum_iter_type!($res, $res); - } - - impl<'a> Sum<&'a $res> for $res { - impl_sum_iter_type!($res, &'a $res); - } - }; - - ($res:ty, $item:ty) => { - fn sum(iter: I) -> Self + impl Sum for $res where - I: Iterator + $res: Add { - iter.fold(Zero::zero(), <$res>::add) + fn sum(iter: I) -> Self + where + I: Iterator + { + iter.fold(Zero::zero(), <$res>::add) + } } }; } macro_rules! impl_product_iter_type { ($res:ty) => { - impl Product for $res { - impl_product_iter_type!($res, $res); - } - - impl<'a> Product<&'a $res> for $res { - impl_product_iter_type!($res, &'a $res); - } - }; - - ($res:ty, $item:ty) => { - fn product(iter: I) -> Self + impl Product for $res where - I: Iterator + $res: Mul { - iter.fold(One::one(), <$res>::mul) + fn product(iter: I) -> Self + where + I: Iterator + { + iter.fold(One::one(), <$res>::mul) + } } }; } diff --git a/src/tests/bigint.rs b/src/tests/bigint.rs index f2431951..386c3dd0 100644 --- a/src/tests/bigint.rs +++ b/src/tests/bigint.rs @@ -1249,3 +1249,23 @@ fn test_iter_product() { assert_eq!(result, data.iter().product()); assert_eq!(result, data.into_iter().product()); } + +#[test] +fn test_iter_sum_generic() { + let result: BigInt = FromPrimitive::from_isize(-1234567).unwrap(); + let data = vec![-1000000, -200000, -30000, -4000, -500, -60, -7]; + + assert_eq!(result, data.iter().sum()); + assert_eq!(result, data.into_iter().sum()); +} + +#[test] +fn test_iter_product_generic() { + let data = vec![1001, -1002, 1003, -1004, 1005]; + let result = data[0].to_bigint().unwrap() * data[1].to_bigint().unwrap() + * data[2].to_bigint().unwrap() * data[3].to_bigint().unwrap() + * data[4].to_bigint().unwrap(); + + assert_eq!(result, data.iter().product()); + assert_eq!(result, data.into_iter().product()); +} diff --git a/src/tests/biguint.rs b/src/tests/biguint.rs index c62a8ad0..9ff4469d 100644 --- a/src/tests/biguint.rs +++ b/src/tests/biguint.rs @@ -1709,3 +1709,23 @@ fn test_iter_product() { assert_eq!(result, data.iter().product()); assert_eq!(result, data.into_iter().product()); } + +#[test] +fn test_iter_sum_generic() { + let result: BigUint = FromPrimitive::from_isize(1234567).unwrap(); + let data = vec![1000000_u32, 200000, 30000, 4000, 500, 60, 7]; + + assert_eq!(result, data.iter().sum()); + assert_eq!(result, data.into_iter().sum()); +} + +#[test] +fn test_iter_product_generic() { + let data = vec![1001_u32, 1002, 1003, 1004, 1005]; + let result = data[0].to_biguint().unwrap() * data[1].to_biguint().unwrap() + * data[2].to_biguint().unwrap() * data[3].to_biguint().unwrap() + * data[4].to_biguint().unwrap(); + + assert_eq!(result, data.iter().product()); + assert_eq!(result, data.into_iter().product()); +} From 60910893ffab819e9561b57f09ba4fa64608a955 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 26 Feb 2018 17:11:48 -0800 Subject: [PATCH 3/3] rust-1.15: avoid Self in constraint --- src/macros.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index 733af73a..8a89bc06 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -319,7 +319,7 @@ macro_rules! impl_sum_iter_type { ($res:ty) => { impl Sum for $res where - $res: Add + $res: Add { fn sum(iter: I) -> Self where @@ -335,7 +335,7 @@ macro_rules! impl_product_iter_type { ($res:ty) => { impl Product for $res where - $res: Mul + $res: Mul { fn product(iter: I) -> Self where