This function is significantly slower than all others so includes an
override in `EXTREMELY_SLOW_TESTS`. Without it, PR CI takes ~1hour and
the extensive tests in CI take ~1day.
Certain functions (`fmodf128`) are significantly slower than others,
to the point that running the default number of tests adds tens of
minutes to PR CI and extensive test time increases to ~1day. It does not
make sense to do this by default; so, introduce `EXTREMELY_SLOW_TESTS`
to test configuration that allows setting specific tests that need to
have a reduced iteration count.
Currently our XFAILs are open ended; we do not check that it actually
fails, so we have no easy way of knowing that a previously-failing test
starts passing. Introduce a new enum that we return from overrides to
give us more flexibility here, including the ability to assert that
expected failures happen.
With the new enum, it is also possible to specify ULP via return value
rather than passing a `&mut u32` parameter.
This includes refactoring of `precision.rs` to be more accurate about
where errors come from, if possible.
Fixes: https://github.com/rust-lang/libm/issues/455
`exp` does not perform any form of unbiasing, so there isn't any reason
it should be signed. Change this.
Additionally, add `EPSILON` to the `Float` trait.
`cc` automatically reads this from Cargo's `OPT_LEVEL` variable so we
don't need to set it explicitly. Remove this so running in a debugger
makes more sense.
This failed a couple of times recently in CI, once on i686 and once on
aarch64-apple:
thread 'main' panicked at crates/libm-test/benches/random.rs:76:65:
called `Result::unwrap()` on an `Err` value: ynf
Caused by:
0:
input: (681, 509.90924) (0x000002a9, 0x43fef462)
expected: -3.2161271e38 0xff71f45b
actual: -inf 0xff800000
1: mismatched infinities
thread 'main' panicked at crates/libm-test/benches/random.rs:76:65:
called `Result::unwrap()` on an `Err` value: ynf
Caused by:
0:
input: (132, 50.46604) (0x00000084, 0x4249dd3a)
expected: -3.3364996e38 0xff7b02a5
actual: -inf 0xff800000
1: mismatched infinities
Add a new override to account for this.
The icount benchmarks are what we will be relying on in CI more than the
existing benchmarks. There isn't much reason to keep these around, but
there isn't much point in dropping them either. So, just reduce the
runtime.
Running walltime benchmarks in CI is notoriously unstable, Introduce
benchmarks that instead use instruction count and other more
reproducible metrics, using `iai-callgrind` [1], which we are able to
run in CI with a high degree of reproducibility.
Inputs to this benchmark are a logspace sweep, which gives an
approximation for real-world use, but may fail to indicate outlier
cases.
[1]: https://github.com/iai-callgrind/iai-callgrind
This also allows reusing the same generator logic between logspace tests
and extensive tests, so comes with a nice bit of cleanup.
Changes:
* Make the generator part of `CheckCtx` since a `Generator` and
`CheckCtx` are almost always passed together.
* Rename `domain_logspace` to `spaced` since this no longer only
operates within a domain and we may want to handle integer spacing.
* Domain is now calculated at runtime rather than using traits, which is
much easier to work with.
* With the above, domains for multidimensional functions are added.
* The extensive test generator code tests has been combined with the
domain_logspace generator code. With this, the domain tests have just
become a subset of extensive tests. These were renamed to "quickspace"
since, technically, the extensive tests are also "domain" or "domain
logspace" tests.
* Edge case generators now handle functions with multiple inputs.
* The test runners can be significantly cleaned up and deduplicated.
Introduce a simple binary that can run arbitrary input against any of
the available implementations (musl, MPFR, our libm). This provides an
easy way to check results, or run specific cases against a debugger.
Examples:
$ cargo run -p util -- eval libm pow 1.6 2.4
3.089498284311124
$ cargo run -p util -- eval mpfr pow 1.6 2.4
3.089498284311124
$ cargo run -p util -- eval musl tgamma 1.2344597839132
0.9097442657960874
$ cargo run -p util -- eval mpfr tgamma 1.2344597839132
0.9097442657960874
$ cargo run -p util -- eval libm tgamma 1.2344597839132
0.9097442657960871
$ cargo run -p util -- eval musl sincos 3.1415926535
(8.979318433952318e-11, -1.0)
Most users who are developing this crate are likely running on a Unix
system, since there isn't much to test against otherwise. For
convenience, enable the features required to run these tests by default.
Currently the features that control what we test against are
`build-musl` and `test-multiprecision`. I didn't name them very
consistently and there isn't really any reason for that.
Rename `test-multiprecision` to `build-mpfr` to better reflect what it
actually does and to be more consistent with `build-musl`.
There was a recent failure from the random tests:
---- mp_random_exp2f stdout ----
Random Mpfr exp2f arg 1/1: 10000 iterations (10000 total) using `LIBM_SEED=fqgMuzs6eqH1VZSEmQpLnThnaIyRUOWe`
thread 'mp_random_exp2f' panicked at crates/libm-test/tests/multiprecision.rs:41:49:
called `Result::unwrap()` on an `Err` value:
input: (127.97238,) (0x42fff1dc,)
expected: 3.3383009e38 0x7f7b2556
actual: inf 0x7f800000
Caused by:
mismatched infinities
Add an xfail for mismatched infinities on i586.
`rint` had a couple recent failures from the random tests:
---- mp_random_rint stdout ----
Random Mpfr rint arg 1/1: 10000 iterations (10000 total) using `LIBM_SEED=Fl1f69DaJnwkHN2FeuCXaBFRvJYsPvEY`
thread 'mp_random_rint' panicked at crates/libm-test/tests/multiprecision.rs:41:49:
called `Result::unwrap()` on an `Err` value:
input: (-849751480.5001163,) (0xc1c95316dc4003d0,)
expected: -849751481.0 0xc1c95316dc800000
actual: -849751480.0 0xc1c95316dc000000
Caused by:
ulp 8388608 > 100000
And:
---- mp_random_rint stdout ----
Random Mpfr rint arg 1/1: 10000 iterations (10000 total) using `LIBM_SEED=XN7VCGhX3Wu6Mzn8COvJPITyZlGP7gN7`
thread 'mp_random_rint' panicked at crates/libm-test/tests/multiprecision.rs:41:49:
called `Result::unwrap()` on an `Err` value:
input: (-12493089.499809155,) (0xc167d4242ffe6fc5,)
expected: -12493089.0 0xc167d42420000000
actual: -12493090.0 0xc167d42440000000
Caused by:
ulp 536870912 > 100000
It seems we just implement an incorrect rounding mode. Replace the
existing `rint` override with an xfail if the difference is 0.0 <= ε <=
1.0.
`compiler_builtins` exposes an `extern "C"` version of `libm` routines,
so add the same here. There really isn't much to test here (unless we
later add tests against C `libm` suites), but one nice benefit is this
gives us a library with unmangled names that is easy to `objdump`. In
accordance with that, also update `cb` to be a `staticlib`.
Unfortunately this also means we have to remove it from the workspace,
since Cargo doesn't allow setting `panic = "abort"` for a single crate.
`ExpInt` is likely to only have performance benefits on 16-bit
platforms, but makes working with the exponent more difficult. It seems
like a worthwhile tradeoff to instead just use `i32`, so do that here.
Update test traits to support `f16` and `f128`, as applicable. Add the
new routines (`fabs` and `copysign` for `f16` and `f128`) to the list of
all operations.
Add a generator that will test all inputs for input spaces `u32::MAX` or
smaller (e.g. single-argument `f32` routines). For anything larger,
still run approximately `u32::MAX` tests, but distribute inputs evenly
across the function domain.
Since we often only want to run one of these tests at a time, this
implementation parallelizes within each test using `rayon`. A custom
test runner is used so a progress bar is possible.
Specific tests must be enabled by setting the `LIBM_EXTENSIVE_TESTS`
environment variable, e.g.
LIBM_EXTENSIVE_TESTS=all_f16,cos,cosf cargo run ...
Testing on a recent machine, most tests take about two minutes or less.
The Bessel functions are quite slow and take closer to 10 minutes, and
FMA is increased to run for about the same.