【发布时间】:2019-12-23 03:02:21
【问题描述】:
在计算数字的阶乘时,我使用了num::BigUInt 类型来避免整数溢出。
但是,我不得不求助于使用 .clone() 来通过 rustc 的借用检查器。
如何重构阶乘函数以避免多次克隆可能很大的数字?
use num::{BigUint, FromPrimitive, One};
fn main() {
for n in -2..33 {
let bign: Option<BigUint> = FromPrimitive::from_isize(n);
match bign {
Some(n) => println!("{}! = {}", n, factorial(n.clone())),
None => println!("Number must be non-negative: {}", n),
}
}
}
fn factorial(number: BigUint) -> BigUint {
if number < FromPrimitive::from_usize(2).unwrap() {
number
} else {
number.clone() * factorial(number - BigUint::one())
}
}
我尝试在函数定义中使用对 BigUInt 的引用,但出现一些错误,指出 BigUInt 不支持引用。
【问题讨论】:
-
BigUint应该支持引用就好了。你肯定可以使用足够多的引用(在小情况下只有一个.clone())——但这仍然涉及许多低效的中间BigUint值。就地乘法是正确的方法,就像 mcarton 的回答一样。 (如果您仍然想要一些递归,可以将其转换为尾递归。) -
@Ry 我不认为原地相乘更有效。事实上,
x *= y就是essentially implemented asx = x * y,所以无论如何你都会得到临时分配。 (并且没有办法避免这种情况,因为大整数乘法的实现需要在计算乘积时访问操作数。) -
factorial(0)是1不是0 -
@SvenMarnach:我认为当你还拥有
y时这是可以避免的……但我可能会误会。 -
@Ry 在计算乘积时,您需要为操作数和结果提供内存。您不能只用结果覆盖其中一个操作数,因为这两个操作数都是完成计算所必需的。许多整数乘法算法需要在此基础上进行临时存储。无论如何,这并不是 Rust 特有的。
标签: reference rust pass-by-reference biginteger borrow-checker