rust-num / num-rational

Generic Rational numbers for Rust
Apache License 2.0
142 stars 50 forks source link

test_ldexp failure on armel #111

Open sebastinas opened 1 year ago

sebastinas commented 1 year ago

Hi,

with the update to 0.4.1, we see the following test failure in Debian on our armel (armv5te-unknown-linux-gnueabi) architecture:

---- test::test_ldexp stdout ----
thread 'test::test_ldexp' panicked at 'assertion failed: `(left == right)`
  left: `2.2250738585072014e-308`,
 right: `0.0`', src/lib.rs:3090:9
stack backtrace:
   0: rust_begin_unwind
             at /usr/src/rustc-1.63.0/library/std/src/panicking.rs:584:5
   1: core::panicking::panic_fmt
             at /usr/src/rustc-1.63.0/library/core/src/panicking.rs:142:14
   2: core::panicking::assert_failed_inner
   3: core::panicking::assert_failed
             at /usr/src/rustc-1.63.0/library/core/src/panicking.rs:181:5
   4: num_rational::test::test_ldexp
             at /usr/share/cargo/registry/num-rational-0.4.1/src/lib.rs:3090:9
   5: num_rational::test::test_ldexp::{{closure}}
             at /usr/share/cargo/registry/num-rational-0.4.1/src/lib.rs:3072:5
   6: core::ops::function::FnOnce::call_once
             at /usr/src/rustc-1.63.0/library/core/src/ops/function.rs:248:5
   7: core::ops::function::FnOnce::call_once
             at /usr/src/rustc-1.63.0/library/core/src/ops/function.rs:248:5

See https://buildd.debian.org/status/fetch.php?pkg=rust-num-rational&arch=armel&ver=0.4.1-1&stamp=1671490743&raw=0 for the full log.

plugwash commented 1 year ago

My conclusion after some experimentation is that this appears to be an issue in the underlying floating point implementation. Specifically it seems that powi and division (but not multiplication) on armel underflows to zero earlier than it should. I did some testing with gcc and clang and couldn't reproduce the issue, so this seems to be rust specific.

The good news is, this only seems to affect the test code, not the code under test.

My first suspicion was that powi was responsible, so I replaced it with my own naive implementation, that failed too. However after some tweaking I managed to produce a powi function that produces the correct results. Specifically the key seems to be after raising to the positive equivilent of power rather than doing 1 / x directly, I do 2 / x and then multiply by 0.5.

I'm going to make an upload to Debian working around this issue soon.

cuviper commented 1 year ago

thread 'test::test_ldexp' panicked at 'assertion failed: (left == right) left: 2.2250738585072014e-308, right: 0.0', src/lib.rs:3090:9

The left is what this crate computes, and that is the correct value, the same as f64::MIN_POSITIVE. But the right 2f64.powi(MIN_EXP - 1) is what underflowed to zero, and that implementation is using an intrinsic. I'm not sure what that lowers to on arm, but this may be worth a Rust bug. For the test in this crate we could just switch directly to MIN_POSITIVE.