I am beginning to study the language rust and, as I usually do to compare with other languages, I want to implement the factorial calculation for large numbers (aka "BigInts" ).
I use the version rust 1.9.0 (stable) , which forces me to search outside the standard library crate to use large numbers ( crate num ). On the other hand, you can not use unstable characteristics of the language such as the aggregation methods sum
or product
, which you have to reimplement using fold
.
At the moment, I have implemented three versions:
extern crate num_bigint;
extern crate num_traits;
extern crate num_iter;
use num_bigint::BigUint;
use num_traits::{Zero, One};
use num_iter::range_inclusive;
fn fact(n: usize) -> BigUint {
let mut res: BigUint = One::one();
for i in 2..n + 1 {
res = res * BigUint::from(i);
}
res
}
fn fact2(n: usize) -> BigUint {
(2..n + 1).fold(One::one(), |x, y| x * BigUint::from(y))
}
fn fact3(n: usize) -> BigUint {
range_inclusive(One::one(), BigUint::from(n)).fold(BigUint::one(), std::ops::Mul::mul)
}
I am interested, above all, in the functional orientation of the language as it appears in the last two implementations.
Although rust should be quite fast in execution, these implementations are much slower than others made in other languages (haskell, python, scala, ...). Also, the code seems inelegant to me. For that:
- Is it possible to improve these implementations to be faster?
- Can you rewrite this code to make it more elegant and / or functional?
-
Any better implementation?
-
Maybe with a macro you could make readable the code?
I add time estimation
Without being anything precise, I add the times obtained with different languages for the calculation of 150000!
to make a better idea:
haskell 25.68 secs
python 15.20 secs
rust[1] 17.67 secs
scala 8.36 secs
scala[2] 2.32 secs
scala[3] 0.32 secs
[1] compilado en rust con optimizaciones completas
[2] usando las colecciones paralelizables de scala
[3] algoritmo paralelizable en scala (https://github.com/chemacortes/factPar)
In addition to times, memory consumption should be measured. In this aspect, yes that the rust version stands out for the little memory used.
Edit [d: 2016-07-28]: I was able to confirm that the crate num
I use has some bugs that make it impossible to use the product
method in iterators BigUint
that would be perfect for the implementation of the factorial. You will have to be patient until ecosistema rust
ripens and pull with "workarounds" , even if they are not as elegant as they should be.