Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experimentation with libm #768

Closed
wants to merge 797 commits into from
Closed

Conversation

tgross35
Copy link
Contributor

Experimentation for #765

tgross35 and others added 30 commits December 27, 2024 11:02
Rather than always needing to exclude `cb` when running `cargo clippy`,
just disable Clippy for the included module.
GitHub will be upgrading the `-latest` tags of these images in the near
future. Change all images to specify the latest version.
Add generic versions of `abs` and `copysign`, which will provide an
entrypoint for adding `f16` and `f128`. Since this implementation is
identical to the existing type-specific implementations, make use of it
for `f32` and `f64`.
In preparation of adding routines from these two types, duplicate the
`compiler-builtins` configuration here.
Since these add new API but do not affect runtime, we can enable it for
all tests that run with nightly.
Add a constant for negative pi and provide a standalone const
`from_bits`, which can be combined with what we already had in
`hex_float`. Also provide another default method to reduce what needs to
be provided by the macro.
Introduce `f8`, which is an 8-bit float compliant with IEEE-754. This
type is useful for testing since it is easily possible to enumerate all
values.
Create a type representing a function's domain and a test that does a
logarithmic sweep of points within the domain.
Introduce a generator that will tests various points of interest
including zeros, infinities, and NaNs.
For visualization, add a simple script for generating scatter plots and
a binary (via examples) to plot the inputs given various domains.
Introduce generators that respect function domains
This will enable us to `include!` the file to access these types in
`libm-test`, rather than somehow reproducing the types as part of the
macro. Ideally `libm-test` would just `use` the types from `libm-macros`
but proc macro crates cannot currently export anything else.

This also adjusts naming to closer match the scheme described in
`libm_test::op`.
These types from `libm-macros` provide a way to get information about an
operation at runtime, rather than only being encoded in the type system.
Include the file and reexport relevant types.
These allow for more convenient printing, as well as storage in map
types.
Introduce new API to iterate the function list and associate items with
their `MathOp`.
Share a list of all functions between `libm-macros` and `libm-test`
These are used more places than just test traits, so this new module
should be a better home. `run_cfg` will also be expanded in the near
future.
Rather than passing names or identifiers, just pass `CheckCtx` in a few
more places.
It is currently getting the default of 1 or 2. Since this operation
should always be infinite precision, no deviation is allowed.
Currently `logspace` does a lossy cast from `F::Int` to `usize`. This
could be problematic in the rare cases that this is called with a step
count exceeding what is representable in `usize`.

Resolve this by instead adding bounds so the float's integer type itself
can be iterated.
We want to be able to adjust our configuration based on whether we are
running in CI, propagate this so our tests can use it.
Rather than collecting a list of file names in `libm-test/build.rs`,
just use a script to parse rustdoc's JSON output.
Now that we are using rustdoc output to locate public functions, the
test is indicating a few that were missed since they don't have their
own function. Update everything to now include the following routines:

* `erfc`
* `erfcf`
* `y0`
* `y0f`
* `y1`
* `y1f`
* `yn`
* `ynf`
Use `rustdoc` JSON for API list, add functions that were missing
Many routines have some form of handling for rounding mode and floating
point exceptions, which are implemented via a combination of stubs and
`force_eval!` use. This is suboptimal, however, because:

1. Rust does not interact with the floating point environment, so most
   of this code does nothing.
2. The parts of the code that are not dead are not testable.
3. `force_eval!` blocks optimizations, which is unnecessary because we
   do not rely on its side effects.

We cannot ensure correct rounding and exception handling in all cases
without some form of arithmetic operations that are aware of this
behavior. However, the cases where rounding mode is explicitly handled
or exceptions are explicitly raised are testable. Make this possible
here for functions that depend on `math::fenv` by moving the
implementation to a nonpublic function that takes a `Round` and returns
a `Status`.

Link: rust-lang/libm#480
Migrate away from nonfunctional `fenv` stubs
Print errors immediately rather than deferring to the end, so any debug
output shows up immediately before the relevant failed test.
These don't have much content since they now use the generic
implementation. There will be more similar functions in the near future
(fminimum, fmaximum, fminimum_num, fmaximum_num); start the pattern of
combining similar functions now so we don't have to eventually maintain
similar docs across 24 different files.
These functions represent new operations from IEEE 754-2019. Introduce
them for all float sizes.
Failed with

    called `Result::unwrap()` on an `Err` value: ynf

    Caused by:
        0:
               input:    (223, 116.89665)
               as hex:   (, 0x1.d3962cp+6)
               as bits:  (0x000000df, 0x42e9cb16)
               expected: -3.1836905e38          -0x1.df074cp+127 0xff6f83a6
               actual:   -inf                   -inf 0xff800000
        1: mismatched infinities
C23 specifies a new set of `roundeven` functions that round to the
nearest integral, with ties to even. It does not raise any floating
point exceptions.

This behavior is similar to two other functions:

1. `rint`, which rounds to the nearest integer respecting rounding mode
   and possibly raising exceptions.
2. `nearbyint`, which is identical to `rint` except it may not raise
   exceptions.

Technically `rint`, `nearbyint`, and `roundeven` all behave the same in
Rust because we assume default floating point environment. The backends
are allowed to lower to `roundeven`, however, so we should provide it in
case the fallback is needed.

Add the `roundeven` family here and convert `rint` to a function that
takes a rounding mode. This currently has no effect.
Inputs in `case_list` shouldn't hit xfails or increased ULP tolerance.
Ensure that overrides are skipped when testing against MPFR or a
specified value and that NaNs, if any, are checked bitwise.
Our function to get the exponent conflicts with the inherent `exp`
function for `e^x`. Rename `exp` to `ex` to avoid confusion and usage
problems.
When there is a panic in an extensive test, tracing down where it came
from can be difficult since no information is provides (messeges are
e.g. "attempted to subtract with overflow"). Resolve this by calling the
functions within `panic::catch_unwind`, printing the input, and
continuing.
Currently the argument multiplier and large float multiplier happen
before selecting count based on generator. However, this means that
bivariate and trivariate functions don't get scaled at all (except for
the special cased fma).

Move this scaling to a later point.
Done in stages so git tracks the moved file correctly.
Done in stages so git tracks the moved file correctly.
Similar to other recent changes, just put public API in the same file as
its generic implementation. To keep things slightly cleaner, split the
default implementation from the `_wide` implementation.

Also introduces a stub `fmaf16`.
Combine `fma` public API with its implementation
This avoids matching build directories, ignored files, and submodules.
Pin aarch64-unknown-linux-gnu and aarch64-apple-darwin to
nightly-2025-02-07 until [1] makes it to a Rust nightly.

[1]: llvm/llvm-project#127804
In `compiler-builtins`, `libm` is contained within a `math` module. The
smoke test in this repo has a slightly different layout so some things
were passing that shouldn't be.

Change module layouts in `compiler-builtins-smoke-test` to match
`compiler-builtins` and update a few instances of broken paths.
`compiler-builtins` is not allowed to call anything from `core`;
however, there are a couple of cases where we do so in `libm` for debug
output. Gate relevant locations behind the `compiler-builtins` Cargo
feature.
These are still causing errors in the compiler-builtins CI.
This requires privately reexporting `libm`'s `support` module at crate
root, where it is expected for macros. Once `libm` is made always
available, the reexport can be simplified.

This delta adds a lot of routines to `f16` and `f128`:

* ceil
* floor
* fma (f128 only)
* fmax
* fmin
* fmod
* ldexp
* rint
* round
* scalbn
* sqrt

Additionally, the following new API was added for all four float types:

* fmaximum
* fmaximum_num
* fminimum
* fminimum_num
* roundeven

There are also some significant performance improvements for `sqrt` and
`sqrtf`, as well as precision improvements for `cbrt` (both `f32` and
`f64` versions of this function are now always correctly rounded).
git-subtree-dir: libm
git-subtree-mainline: d3ae7bf
git-subtree-split: cb14a23
@tgross35 tgross35 closed this Feb 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants