代码之家  ›  专栏  ›  技术社区  ›  blokeley SERPRO

如何避免在rust中克隆大整数

  •  0
  • blokeley SERPRO  · 技术社区  · 6 年前

    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不支持引用。

    1 回复  |  直到 6 年前
        1
  •  2
  •   mcarton    6 年前

    第一个 clone 很容易移除。你想用 n 在同一表达式中有两次,因此不要只使用一个表达式:

    print!("{}! = ", n);
    println!("{}", factorial(n));
    

    相当于 println!("{}! = {}", n, factorial(n.clone())) n 同时引用它。

    第二次 factorial 不递归:

    fn factorial(mut number: BigUint) -> BigUint {
        let mut result = BigUint::one();
        let one = BigUint::one();
    
        while number > one {
            result *= &number;
            number -= &one;
        }
    
        result
    }
    

    然而,这似乎是不符合逻辑的。有一个 range 函数,可以与一起使用 for 但是,它使用 从内部来看,这一点是错误的。

        2
  •  1
  •   Stargateur    6 年前

    BigUint 作为参数对阶乘是有意义的。 u32 应该足够了:

    use num::{BigUint, One};
    
    fn main() {
        for n in 0..42 {
            println!("{}! = {}", n, factorial(n));
        }
    }
    
    fn factorial_aux(accu: BigUint, i: u32) -> BigUint {
        if i > 1 {
            factorial_aux(accu * i, i - 1)
        }
        else {
            accu
        }
    }
    
    fn factorial(n: u32) -> BigUint {
        factorial_aux(BigUint::one(), n)
    }
    

    或者如果你真的想 偏执 :

    use num::{BigUint, FromPrimitive, One, Zero};
    
    fn main() {
        for i in (0..42).flat_map(|i| FromPrimitive::from_i32(i)) {
            print!("{}! = ", i);
            println!("{}", factorial(i));
        }
    }
    
    fn factorial_aux(accu: BigUint, i: BigUint) -> BigUint {
        if !i.is_one() {
            factorial_aux(accu * &i, i - 1u32)
        } else {
            accu
        }
    }
    
    fn factorial(n: BigUint) -> BigUint {
        if !n.is_zero() {
            factorial_aux(BigUint::one(), n)
        } else {
            BigUint::one()
        }
    }
    

    两个版本都不做任何克隆。