0

I have the following code snippet:

use num_bigint::*; // 0.2.2
use num_traits::*; // 0.2.8
use std::ops::*;

fn xgcd(b: &BigInt, a: &BigInt) -> (BigInt, BigInt, BigInt) {
    let mut x0: BigInt = One::one();
    let mut x1: BigInt = Zero::zero();
    let mut y0: BigInt = Zero::zero();
    let mut y1: BigInt = One::one();
    let mut q = 0;
    while a != Zero::zero() {
        q = b.div(a);
        b = a;
        a = &b.rem(a);
        x0 = x1;
        x1 = x0 - q * x1;
        y0 = y1;
        y1 = y0 - q * y1;
    }
    return (*b, x0, y0);
}

It gives the following error:

error[E0308]: mismatched types
  --> src/lib.rs:12:13
   |
12 |         q = b.div(a);
   |             ^^^^^^^^ expected integer, found struct `num_bigint::bigint::BigInt`
   |
   = note: expected type `{integer}`
              found type `num_bigint::bigint::BigInt`

I've looked up the documentation of num::BigInt and it states that there is in fact a div method with a BigInt as a parameter, but somehow the compiler decides not to use it and instead tells me that I can't divide a BigInt with a BigInt. Is there any way to fix this?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • 2
    notice how `let mut q = 0;` looks different – Ry- Jun 19 '19 at 19:39
  • Besides the `q`'s type do you really want to change the value of the borrowed parameters ? Because looks like there is no implementation of `Div` and `Rem` traits for `&mut BigInt`, you may consider creating new local vars instead – Ömer Erden Jun 19 '19 at 19:46
  • `b = a; a = b % a;` — Since `a` and `b` are the same value, won't `b % a` always result in `1`? Seems like the algorithm is off, or am I missing something? – Shepmaster Jun 19 '19 at 19:54
  • oh yeah i figured that out too. I am trying to port over an algorithm from Python and it changes multiple variables in one line and probably made a pretty big mistake while porting Thank you guys, I really appreciate your help – halbGefressen Jun 19 '19 at 22:11

1 Answers1

6

and instead tells me that I can't divide a BigInt with a BigInt

It does not. It tells you that the result of dividing the two is a BigInt and it needs an {integer}. This is because your q variable has been declared as an integer, not a BigInt. Therefore, the result of the division must be some kind of built-in integer ({integer}), but the result of dividing a BigInt by a BigInt is another BigInt.

You've used Zero::zero everywhere else, so it's unclear why you didn't use it here. Fortunately, you don't need to set it anything because you shouldn't initialize it until inside the loop anyway:

use num_bigint::*; // 0.2.2
use num_traits::*; // 0.2.8

fn xgcd(b: &BigInt, a: &BigInt) -> (BigInt, BigInt, BigInt) {
    let mut a = a.clone();
    let mut b = b.clone();
    let mut x0 = BigInt::one();
    let mut x1 = BigInt::zero();
    let mut y0 = BigInt::zero();
    let mut y1 = BigInt::one();

    while !a.is_zero() {
        let q = &b / &a;
        b = a.clone();
        a = &b % &a;
        x0 = x1.clone();
        x1 = &x0 - &q * x1;
        y0 = y1.clone();
        y1 = &y0 - &q * y1;
    }

    (b, x0, y0)
}

Changes include:

  • The operator forms are used instead of the method names (e.g. / vs div).
  • A number of .clone() calls were added. I didn't ensure that these were the minimal number of clones possible, so check that.
  • A number of & were added to prevent clones in other places.
  • Zero::is_zero can be faster than creating a value and comparing it.
  • The shorter syntax of BigInt::zero() is used.

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • Thank you so much! I didn't notice at all that I didn't use Zero::zero() for declaring q. I just started learning Rust and the concepts of the language are still pretty new to me. You really helped me understand that part better. – halbGefressen Jun 19 '19 at 22:09