I thought that rewriting "Mathematical puzzles to train the programmer's brain" with Rust might be just right for preventing blurring.
Ruby
I feel that pre2_1.rb in the book p.018 does not give the correct answer. By definition, permutation code is
r.upto(n) do |i|
It's not ... So, the code that gives the correct answer.
ex2.rb
require "test/unit"
def nPr(n, r)
result = 1
(n-r+1).upto(n) do |i|
result *= i
end
result
end
def nCr(n,r)
result = 1
1.upto(r) do |i|
result = result * (n - i + 1) / i
end
result
end
class NPrTest < Test::Unit::TestCase
def test_nPr
assert_equal 1, nPr(1,1), "1P1 should return 1."
assert_equal 720, nPr(6,6), "6P6 should return 720."
assert_equal 20, nPr(5,2), "5P2 should return 20."
end
def test_nCr
assert_equal 1, nCr(1,1), "1C1 should return 1."
assert_equal 1, nCr(6,6), "6C6 should return 1."
assert_equal 10, nCr(5,2), "5C2 should return 10."
end
end
Rust
main.rs
fn main() {
println!("{n}P{r} = {x}", n = 5, r = 2, x = permutation(5, 2));
println!("{n}C{r} = {x}", n = 5, r = 2, x = combination(5, 2));
}
pub fn permutation(n: i64, r: i64) -> i64 {
let mut result = 1;
for i in (n - r + 1)..=n {
result *= i;
}
return result;
}
pub fn combination(n: i64, r: i64) -> i64 {
let mut result = 1;
for i in 1..=r {
result = result * (n - i + 1) / i;
}
return result;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_permutation() {
assert_eq!(permutation(1, 1), 1);
assert_eq!(permutation(6, 6), 720);
assert_eq!(permutation(5, 2), 20);
}
#[test]
fn test_combination() {
assert_eq!(combination(1, 1), 1);
assert_eq!(combination(6, 6), 1);
assert_eq!(combination(5, 2), 10);
}
}
Solid transplant. by the way,
result = result * (n - i + 1) / i;
And write
result *= (n - i + 1) / i;
Is it different to write? I'm glad I proceeded while writing the test.
I'm wondering, "How about using mut
all the time? ", But as long as it's closed in one function, I don't think it's too much noise.
I got a concise code example. Experimented as permutation2 ()
and combination2 ()
.
main.rs
fn main() {
println!("{n}P{r} = {x}", n = 5, r = 2, x = permutation(5, 2));
println!("{n}C{r} = {x}", n = 5, r = 2, x = combination(5, 2));
}
pub fn permutation(n: i64, r: i64) -> i64 {
let mut result = 1;
for i in (n - r + 1)..=n {
result *= i;
}
return result;
}
pub fn combination(n: i64, r: i64) -> i64 {
let mut result = 1;
for i in 1..=r {
result = result * (n - i + 1) / i;
}
return result;
}
pub fn permutation2(n: i64, r: i64) -> i64 {
(n - r + 1..=n).product()
}
pub fn combination2(n: i64, r: i64) -> i64 {
(1..=r).fold(1, |p, i| p * (n - i + 1) / i)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_permutation() {
assert_eq!(permutation(1, 1), 1);
assert_eq!(permutation(6, 6), 720);
assert_eq!(permutation(5, 2), 20);
assert_eq!(permutation(1,1), permutation2(1,1));
assert_eq!(permutation(6,6), permutation2(6,6));
assert_eq!(permutation(5,2), permutation2(5,2));
}
#[test]
fn test_combination() {
assert_eq!(combination(1, 1), 1);
assert_eq!(combination(6, 6), 1);
assert_eq!(combination(5, 2), 10);
assert_eq!(combination(1, 1), combination2(1,1));
assert_eq!(combination(6, 6), combination2(6,6));
assert_eq!(combination(5, 2), combination2(5,2));
}
}
Certainly the same result. The code is also easy to understand.
Recommended Posts