# Why does 0 <= 0 panics here?

Hi all,
so I'm trying learning Rust from the Exercism track. In this exercise, I want to write a function that computes the "length" of a number, in the sense of powers of ten, i.e. the number of digits.
I need to work with `BigInt`s, from crate `num_bigint`. Now, this code panics if I try to compute the length of `BigInt::from(0)`:

``````pub fn length(test: &BigInt) -> BigInt {
let mut res = BigInt::from(0);
let mut temp = BigInt::from(1);
while &temp <= test {
dbg!(&temp);
res += 1;
temp *= 10;
}
res
}
``````

In particular, seeing the outputs from the `dbg!()` call, it seems like the comparison `&temp <= test` causes some error. But why? Shouldn't it be just `0 <= 0`? I've tested with other values, like `BigInt::from(1)`, and it works. What am I doing wrong?Can I fix this?

Thanks!

I can't reproduce.

Best guess, you're not expecting a 0 return and are dividing by it or doing something else that can't work with 0. Special-case 0 to return 1 maybe.

1 Like

What is the actual panic message? Did you set `RUST_BACKTRACE=1` as it suggests to see exactly what the call path was to that point?

Thanks to both, I'm adding a bit of context. The panic happens in this test:

``````use decimal::{Decimal, length};
use num_bigint::BigInt;
// custom
#[test]
fn length_single_digit() {
assert!(length(&BigInt::from(1)) == BigInt::from(1));
assert!(length(&BigInt::from(2)) == BigInt::from(1));
assert!(length(&BigInt::from(5)) == BigInt::from(1));
assert!(length(&BigInt::from(9)) == BigInt::from(1));
assert!(length(&BigInt::from(0)) == BigInt::from(1));
}
``````

``````pub fn length(test: &BigInt) -> BigInt {
let mut res = BigInt::from(0);
let mut temp = BigInt::from(1);
dbg!(test);
dbg!(&temp);
while &temp <= test {
dbg!(&temp);
res += 1;
temp *= 10;
}
res
}
``````

Running with RUST_BACKTRACE=1, I got:

``````failures:

---- length_single_digit stdout ----
[src/lib.rs:22] test = 1
[src/lib.rs:23] &temp = 1
[src/lib.rs:25] &temp = 1
[src/lib.rs:22] test = 2
[src/lib.rs:23] &temp = 1
[src/lib.rs:25] &temp = 1
[src/lib.rs:22] test = 5
[src/lib.rs:23] &temp = 1
[src/lib.rs:25] &temp = 1
[src/lib.rs:22] test = 9
[src/lib.rs:23] &temp = 1
[src/lib.rs:25] &temp = 1
[src/lib.rs:22] test = 0
[src/lib.rs:23] &temp = 1
thread 'length_single_digit' panicked at 'assertion failed: length(&BigInt::from(0)) == BigInt::from(1)', tests/decimal.rs:25:5
stack backtrace:
0: rust_begin_unwind
at /rustc/90743e7298aca107ddaa0c202a4d3604e29bfeb6/library/std/src/panicking.rs:575:5
1: core::panicking::panic_fmt
at /rustc/90743e7298aca107ddaa0c202a4d3604e29bfeb6/library/core/src/panicking.rs:65:14
2: core::panicking::panic
at /rustc/90743e7298aca107ddaa0c202a4d3604e29bfeb6/library/core/src/panicking.rs:115:5
3: decimal::length_single_digit
at ./tests/decimal.rs:25:5
4: decimal::length_single_digit::{{closure}}
at ./tests/decimal.rs:20:1
5: core::ops::function::FnOnce::call_once
at /rustc/90743e7298aca107ddaa0c202a4d3604e29bfeb6/library/core/src/ops/function.rs:251:5
6: core::ops::function::FnOnce::call_once
at /rustc/90743e7298aca107ddaa0c202a4d3604e29bfeb6/library/core/src/ops/function.rs:251:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
``````

Inspecting it with the debugger of VSCode, it seems like it's not the code that panics, but the test. Apparently, `BigInt`s codifiy 0 as an empty vector, and not a vector containing `0`. May this be the problem?

It has nothing to do with the internal representation of `BigInt`s; the equivalent code for `i32` will do the same thing:

``````#[test]
fn length_single_digit() {
assert_eq!(length(1), 1);
assert_eq!(length(2), 1);
assert_eq!(length(5), 1);
assert_eq!(length(9), 1);
assert_eq!(length(0), 1);
}

pub fn length(test: i32) -> i32 {
let mut res = 0;
let mut temp = 1;
while temp <= test {
res += 1;
temp *= 10;
}
res
}
``````

Before the first loop iteration, `temp` is 1 and `test` is 0, so `temp <= test` is false and the loop never runs. You then return the initial value of `res`, which is zero.

Also, this code is incorrect for negative numbers: `temp *= 10` will always make `temp` get smaller, and the loop will run until `temp` overflows.

Edit: I got things backwards in the struck-out text above. Negative inputs will always return zero here through the same path as a `0`, and there will be no overflow in this case.

7 Likes

You're completely right, thanks! Now I feel a little dumby... This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.