Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

1
vendor/libm/.cargo-checksum.json vendored Normal file

File diff suppressed because one or more lines are too long

229
vendor/libm/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,229 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [0.2.15](https://github.com/rust-lang/compiler-builtins/compare/libm-v0.2.14...libm-v0.2.15) - 2025-05-06
### Other
- Require `target_has_atomic = "ptr"` for runtime feature detection
## [0.2.14](https://github.com/rust-lang/compiler-builtins/compare/libm-v0.2.13...libm-v0.2.14) - 2025-05-03
### Other
- Use runtime feature detection for fma routines on x86
## [0.2.13](https://github.com/rust-lang/compiler-builtins/compare/libm-v0.2.12...libm-v0.2.13) - 2025-04-21
### Fixed
- Switch back to workspace resolver v2 to unbreak builds without the 2024 edition
## [0.2.12](https://github.com/rust-lang/compiler-builtins/compare/libm-v0.2.11...libm-v0.2.12) - 2025-04-21
- Mark generic functions `#[inline]`
- Combine the source files for `fmod`
- Ensure all public functions are marked `no_panic`
- Add assembly version of simple operations on aarch64
- Add `roundeven{,f,f16,f128}`
- Add `fminimum`, `fmaximum`, `fminimum_num`, and `fmaximum_num`
- Eliminate the use of `force_eval!` in `ceil`, `floor`, and `trunc`
- Port the CORE-MATH version of `cbrt`
- Add `fmaf128`
- fma: Ensure zero has the correct sign
- Add `scalbnf16`, `scalbnf128`, `ldexpf16`, and `ldexpf128`
- Specify license as just MIT
- Add `fmodf128`
- Add `fmodf16` using the generic implementation
- Add `fminf16`, `fmaxf16`, `fminf128`, and `fmaxf128`
- Add `roundf16` and `roundf128`
- Add `rintf16` and `rintf128`
- Add `floorf16` and `floorf128`
- Add `ceilf16` and `ceilf128`
- Add `sqrtf16` and `sqrtf128`
- Simplify and optimize `fdim` ([#442](https://github.com/rust-lang/libm/pull/442))
- Add `fdimf16` and `fdimf128`
- Add `truncf16` and `truncf128`
- Add `fabsf16`, `fabsf128`, `copysignf16`, and `copysignf128`
- Move some numeric trait logic to default implementations
- Add some more basic docstrings ([#352](https://github.com/rust-lang/libm/pull/352))
- Add support for loongarch64-unknown-linux-gnu
- Add an "arch" Cargo feature that is on by default
- Rename the `special_case` module to `precision` and move default ULP
- Move the existing "unstable" feature to "unstable-intrinsics"
There are a number of things that changed internally, see the git log for a full
list of changes.
## [0.2.11](https://github.com/rust-lang/libm/compare/libm-v0.2.10...libm-v0.2.11) - 2024-10-28
### Fixed
- fix type of constants in ported sincosf ([#331](https://github.com/rust-lang/libm/pull/331))
### Other
- Disable a unit test that is failing on i586
- Add a procedural macro for expanding all function signatures
- Introduce `musl-math-sys` for bindings to musl math symbols
- Add basic docstrings to some functions ([#337](https://github.com/rust-lang/libm/pull/337))
## [0.2.10](https://github.com/rust-lang/libm/compare/libm-v0.2.9...libm-v0.2.10) - 2024-10-28
### Other
- Set the MSRV to 1.63 and test this in CI
## [0.2.9](https://github.com/rust-lang/libm/compare/libm-v0.2.8...libm-v0.2.9) - 2024-10-26
### Fixed
- Update exponent calculations in nextafter to match musl
### Changed
- Update licensing to MIT AND (MIT OR Apache-2.0), as this is derivative from
MIT-licensed musl.
- Set edition to 2021 for all crates
- Upgrade all dependencies
### Other
- Don't deny warnings in lib.rs
- Rename the `musl-bitwise-tests` feature to `test-musl-serialized`
- Rename the `musl-reference-tests` feature to `musl-bitwise-tests`
- Move `musl-reference-tests` to a new `libm-test` crate
- Add a `force-soft-floats` feature to prevent using any intrinsics or
arch-specific code
- Deny warnings in CI
- Fix `clippy::deprecated_cfg_attr` on compiler_builtins
- Corrected English typos
- Remove unneeded `extern core` in `tgamma`
- Allow internal_features lint when building with "unstable"
## [v0.2.1] - 2019-11-22
### Fixed
- sincosf
## [v0.2.0] - 2019-10-18
### Added
- Benchmarks
- signum
- remainder
- remainderf
- nextafter
- nextafterf
### Fixed
- Rounding to negative zero
- Overflows in rem_pio2 and remquo
- Overflows in fma
- sincosf
### Removed
- F32Ext and F64Ext traits
## [v0.1.4] - 2019-06-12
### Fixed
- Restored compatibility with Rust 1.31.0
## [v0.1.3] - 2019-05-14
### Added
- minf
- fmin
- fmaxf
- fmax
## [v0.1.2] - 2018-07-18
### Added
- acosf
- asin
- asinf
- atan
- atan2
- atan2f
- atanf
- cos
- cosf
- cosh
- coshf
- exp2
- expm1
- expm1f
- expo2
- fmaf
- pow
- sin
- sinf
- sinh
- sinhf
- tan
- tanf
- tanh
- tanhf
## [v0.1.1] - 2018-07-14
### Added
- acos
- acosf
- asin
- asinf
- atanf
- cbrt
- cbrtf
- ceil
- ceilf
- cosf
- exp
- exp2
- exp2f
- expm1
- expm1f
- fdim
- fdimf
- floorf
- fma
- fmod
- log
- log2
- log10
- log10f
- log1p
- log1pf
- log2f
- roundf
- sinf
- tanf
## v0.1.0 - 2018-07-13
- Initial release
[Unreleased]: https://github.com/japaric/libm/compare/v0.2.1...HEAD
[v0.2.1]: https://github.com/japaric/libm/compare/0.2.0...v0.2.1
[v0.2.0]: https://github.com/japaric/libm/compare/0.1.4...v0.2.0
[v0.1.4]: https://github.com/japaric/libm/compare/0.1.3...v0.1.4
[v0.1.3]: https://github.com/japaric/libm/compare/v0.1.2...0.1.3
[v0.1.2]: https://github.com/japaric/libm/compare/v0.1.1...v0.1.2
[v0.1.1]: https://github.com/japaric/libm/compare/v0.1.0...v0.1.1

56
vendor/libm/Cargo.lock generated vendored Normal file
View File

@@ -0,0 +1,56 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "libm"
version = "0.2.15"
dependencies = [
"no-panic",
]
[[package]]
name = "no-panic"
version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "113d1abd5bb3dc25a75d9b3a973f40e31eb03e0bae23c172b32cca4bcb9cfad2"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "syn"
version = "2.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"

57
vendor/libm/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,57 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2021"
rust-version = "1.63"
name = "libm"
version = "0.2.15"
authors = ["Jorge Aparicio <jorge@japaric.io>"]
build = "build.rs"
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "libm in pure Rust"
documentation = "https://docs.rs/libm"
readme = "README.md"
keywords = [
"libm",
"math",
]
categories = ["no-std"]
license = "MIT"
repository = "https://github.com/rust-lang/compiler-builtins"
[features]
arch = []
default = ["arch"]
force-soft-floats = []
unstable = [
"unstable-intrinsics",
"unstable-float",
]
unstable-float = []
unstable-intrinsics = []
unstable-public-internals = []
[lib]
name = "libm"
path = "src/lib.rs"
[dev-dependencies.no-panic]
version = "0.1.35"
[lints.rust.unexpected_cfgs]
level = "warn"
priority = 0
check-cfg = ['cfg(feature, values("compiler-builtins"))']

258
vendor/libm/LICENSE.txt vendored Normal file
View File

@@ -0,0 +1,258 @@
rust-lang/libm as a whole is available for use under the MIT license:
------------------------------------------------------------------------------
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
As a contributor, you agree that your code can be used under either the MIT
license or the Apache-2.0 license:
------------------------------------------------------------------------------
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
------------------------------------------------------------------------------
This Rust library contains the following copyrights:
Copyright (c) 2018 Jorge Aparicio
Portions of this software are derived from third-party works licensed under
terms compatible with the above MIT license:
* musl libc https://www.musl-libc.org/. This library contains the following
copyright:
Copyright © 2005-2020 Rich Felker, et al.
* The CORE-MATH project https://core-math.gitlabpages.inria.fr/. CORE-MATH
routines are available under the MIT license on a per-file basis.
The musl libc COPYRIGHT file also includes the following notice relevant to
math portions of the library:
------------------------------------------------------------------------------
Much of the math library code (src/math/* and src/complex/*) is
Copyright © 1993,2004 Sun Microsystems or
Copyright © 2003-2011 David Schultz or
Copyright © 2003-2009 Steven G. Kargl or
Copyright © 2003-2009 Bruce D. Evans or
Copyright © 2008 Stephen L. Moshier or
Copyright © 2017-2018 Arm Limited
and labelled as such in comments in the individual source files. All
have been licensed under extremely permissive terms.
------------------------------------------------------------------------------
Copyright notices are retained in src/* files where relevant.

42
vendor/libm/README.md vendored Normal file
View File

@@ -0,0 +1,42 @@
# `libm`
A Rust implementations of the C math library.
## Usage
`libm` provides fallback implementations for Rust's [float math functions] in
`core`, and the [`core_float_math`] feature. If what is available suits your
needs, there is no need to add `libm` as a dependency.
If more functionality is needed, this crate can also be used directly:
```toml
[dependencies]
libm = "0.2.11"
```
[float math functions]: https://doc.rust-lang.org/std/primitive.f32.html
[`core_float_math`]: https://github.com/rust-lang/rust/issues/137578
## Contributing
Please check [CONTRIBUTING.md](../CONTRIBUTING.md)
## Minimum Rust version policy
This crate supports rustc 1.63 and newer.
## License
Usage is under the MIT license, available at
<https://opensource.org/license/mit>.
### Contribution
Contributions are licensed under both the MIT license and the Apache License,
Version 2.0, available at <htps://www.apache.org/licenses/LICENSE-2.0>. Unless
you explicitly state otherwise, any contribution intentionally submitted for
inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as mentioned, without any additional terms or conditions.
See [LICENSE.txt](LICENSE.txt) for full details.

18
vendor/libm/build.rs vendored Normal file
View File

@@ -0,0 +1,18 @@
use std::env;
mod configure;
fn main() {
let cfg = configure::Config::from_env();
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=configure.rs");
println!("cargo:rustc-check-cfg=cfg(assert_no_panic)");
// If set, enable `no-panic`. Requires LTO (`release-opt` profile).
if env::var("ENSURE_NO_PANIC").is_ok() {
println!("cargo:rustc-cfg=assert_no_panic");
}
configure::emit_libm_config(&cfg);
}

189
vendor/libm/configure.rs vendored Normal file
View File

@@ -0,0 +1,189 @@
// Configuration shared with both libm and libm-test
use std::env;
use std::path::PathBuf;
#[allow(dead_code)]
pub struct Config {
pub manifest_dir: PathBuf,
pub out_dir: PathBuf,
pub opt_level: String,
pub cargo_features: Vec<String>,
pub target_arch: String,
pub target_env: String,
pub target_family: Option<String>,
pub target_os: String,
pub target_string: String,
pub target_vendor: String,
pub target_features: Vec<String>,
}
impl Config {
pub fn from_env() -> Self {
let target_features = env::var("CARGO_CFG_TARGET_FEATURE")
.map(|feats| feats.split(',').map(ToOwned::to_owned).collect())
.unwrap_or_default();
let cargo_features = env::vars()
.filter_map(|(name, _value)| name.strip_prefix("CARGO_FEATURE_").map(ToOwned::to_owned))
.map(|s| s.to_lowercase().replace("_", "-"))
.collect();
Self {
manifest_dir: PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()),
out_dir: PathBuf::from(env::var("OUT_DIR").unwrap()),
opt_level: env::var("OPT_LEVEL").unwrap(),
cargo_features,
target_arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(),
target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(),
target_family: env::var("CARGO_CFG_TARGET_FAMILY").ok(),
target_os: env::var("CARGO_CFG_TARGET_OS").unwrap(),
target_string: env::var("TARGET").unwrap(),
target_vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(),
target_features,
}
}
}
/// Libm gets most config options made available.
#[allow(dead_code)]
pub fn emit_libm_config(cfg: &Config) {
emit_intrinsics_cfg();
emit_arch_cfg();
emit_optimization_cfg(cfg);
emit_cfg_shorthands(cfg);
emit_cfg_env(cfg);
emit_f16_f128_cfg(cfg);
}
/// Tests don't need most feature-related config.
#[allow(dead_code)]
pub fn emit_test_config(cfg: &Config) {
emit_optimization_cfg(cfg);
emit_cfg_shorthands(cfg);
emit_cfg_env(cfg);
emit_f16_f128_cfg(cfg);
}
/// Simplify the feature logic for enabling intrinsics so code only needs to use
/// `cfg(intrinsics_enabled)`.
fn emit_intrinsics_cfg() {
println!("cargo:rustc-check-cfg=cfg(intrinsics_enabled)");
// Disabled by default; `unstable-intrinsics` enables again; `force-soft-floats` overrides
// to disable.
if cfg!(feature = "unstable-intrinsics") && !cfg!(feature = "force-soft-floats") {
println!("cargo:rustc-cfg=intrinsics_enabled");
}
}
/// Simplify the feature logic for enabling arch-specific features so code only needs to use
/// `cfg(arch_enabled)`.
fn emit_arch_cfg() {
println!("cargo:rustc-check-cfg=cfg(arch_enabled)");
// Enabled by default via the "arch" feature, `force-soft-floats` overrides to disable.
if cfg!(feature = "arch") && !cfg!(feature = "force-soft-floats") {
println!("cargo:rustc-cfg=arch_enabled");
}
}
/// Some tests are extremely slow. Emit a config option based on optimization level.
fn emit_optimization_cfg(cfg: &Config) {
println!("cargo:rustc-check-cfg=cfg(optimizations_enabled)");
if !matches!(cfg.opt_level.as_str(), "0" | "1") {
println!("cargo:rustc-cfg=optimizations_enabled");
}
}
/// Provide an alias for common longer config combinations.
fn emit_cfg_shorthands(cfg: &Config) {
println!("cargo:rustc-check-cfg=cfg(x86_no_sse)");
if cfg.target_arch == "x86" && !cfg.target_features.iter().any(|f| f == "sse") {
// Shorthand to detect i586 targets
println!("cargo:rustc-cfg=x86_no_sse");
}
}
/// Reemit config that we make use of for test logging.
fn emit_cfg_env(cfg: &Config) {
println!(
"cargo:rustc-env=CFG_CARGO_FEATURES={:?}",
cfg.cargo_features
);
println!("cargo:rustc-env=CFG_OPT_LEVEL={}", cfg.opt_level);
println!(
"cargo:rustc-env=CFG_TARGET_FEATURES={:?}",
cfg.target_features
);
}
/// Configure whether or not `f16` and `f128` support should be enabled.
fn emit_f16_f128_cfg(cfg: &Config) {
println!("cargo:rustc-check-cfg=cfg(f16_enabled)");
println!("cargo:rustc-check-cfg=cfg(f128_enabled)");
// `unstable-float` enables these features.
if !cfg!(feature = "unstable-float") {
return;
}
// Set whether or not `f16` and `f128` are supported at a basic level by LLVM. This only means
// that the backend will not crash when using these types and generates code that can be called
// without crashing (no infinite recursion). This does not mean that the platform doesn't have
// ABI or other bugs.
//
// We do this here rather than in `rust-lang/rust` because configuring via cargo features is
// not straightforward.
//
// Original source of this list:
// <https://github.com/rust-lang/compiler-builtins/pull/652#issuecomment-2266151350>
let f16_enabled = match cfg.target_arch.as_str() {
// Unsupported <https://github.com/llvm/llvm-project/issues/94434>
"arm64ec" => false,
// Selection failure <https://github.com/llvm/llvm-project/issues/50374>
"s390x" => false,
// Infinite recursion <https://github.com/llvm/llvm-project/issues/97981>
// FIXME(llvm): loongarch fixed by <https://github.com/llvm/llvm-project/pull/107791>
"csky" => false,
"hexagon" => false,
"loongarch64" => false,
"mips" | "mips64" | "mips32r6" | "mips64r6" => false,
"powerpc" | "powerpc64" => false,
"sparc" | "sparc64" => false,
"wasm32" | "wasm64" => false,
// Most everything else works as of LLVM 19
_ => true,
};
let f128_enabled = match cfg.target_arch.as_str() {
// Unsupported (libcall is not supported) <https://github.com/llvm/llvm-project/issues/121122>
"amdgpu" => false,
// Unsupported <https://github.com/llvm/llvm-project/issues/94434>
"arm64ec" => false,
// Selection failure <https://github.com/llvm/llvm-project/issues/96432>
"mips64" | "mips64r6" => false,
// Selection failure <https://github.com/llvm/llvm-project/issues/95471>
"nvptx64" => false,
// Selection failure <https://github.com/llvm/llvm-project/issues/101545>
"powerpc64" if &cfg.target_os == "aix" => false,
// Selection failure <https://github.com/llvm/llvm-project/issues/41838>
"sparc" => false,
// Most everything else works as of LLVM 19
_ => true,
};
// If the feature is set, disable these types.
let disable_both = env::var_os("CARGO_FEATURE_NO_F16_F128").is_some();
println!("cargo:rustc-check-cfg=cfg(f16_enabled)");
println!("cargo:rustc-check-cfg=cfg(f128_enabled)");
if f16_enabled && !disable_both {
println!("cargo:rustc-cfg=f16_enabled");
}
if f128_enabled && !disable_both {
println!("cargo:rustc-cfg=f128_enabled");
}
}

33
vendor/libm/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,33 @@
//! libm in pure Rust
#![no_std]
#![cfg_attr(intrinsics_enabled, allow(internal_features))]
#![cfg_attr(intrinsics_enabled, feature(core_intrinsics))]
#![cfg_attr(
all(intrinsics_enabled, target_family = "wasm"),
feature(wasm_numeric_instr)
)]
#![cfg_attr(f128_enabled, feature(f128))]
#![cfg_attr(f16_enabled, feature(f16))]
#![allow(clippy::assign_op_pattern)]
#![allow(clippy::deprecated_cfg_attr)]
#![allow(clippy::eq_op)]
#![allow(clippy::excessive_precision)]
#![allow(clippy::float_cmp)]
#![allow(clippy::int_plus_one)]
#![allow(clippy::just_underscores_and_digits)]
#![allow(clippy::many_single_char_names)]
#![allow(clippy::mixed_case_hex_literals)]
#![allow(clippy::needless_late_init)]
#![allow(clippy::needless_return)]
#![allow(clippy::unreadable_literal)]
#![allow(clippy::zero_divided_by_zero)]
#![forbid(unsafe_op_in_unsafe_fn)]
mod libm_helper;
mod math;
use core::{f32, f64};
pub use libm_helper::*;
pub use self::math::*;

244
vendor/libm/src/libm_helper.rs vendored Normal file
View File

@@ -0,0 +1,244 @@
use core::marker::PhantomData;
use crate::*;
/// Generic helper for libm functions, abstracting over f32 and f64. <br/>
/// # Type Parameter:
/// - `T`: Either `f32` or `f64`
///
/// # Examples
/// ```rust
/// use libm::{self, Libm};
///
/// const PI_F32: f32 = 3.1415927410e+00;
/// const PI_F64: f64 = 3.1415926535897931160e+00;
///
/// assert!(Libm::<f32>::cos(0.0f32) == libm::cosf(0.0));
/// assert!(Libm::<f32>::sin(PI_F32) == libm::sinf(PI_F32));
///
/// assert!(Libm::<f64>::cos(0.0f64) == libm::cos(0.0));
/// assert!(Libm::<f64>::sin(PI_F64) == libm::sin(PI_F64));
/// ```
pub struct Libm<T>(PhantomData<T>);
macro_rules! libm_helper {
($t:ident, funcs: $funcs:tt) => {
impl Libm<$t> {
#![allow(unused_parens)]
libm_helper! { $funcs }
}
};
({$($func:tt;)*}) => {
$(
libm_helper! { $func }
)*
};
((fn $func:ident($($arg:ident: $arg_typ:ty),*) -> ($($ret_typ:ty),*); => $libm_fn:ident)) => {
#[inline(always)]
pub fn $func($($arg: $arg_typ),*) -> ($($ret_typ),*) {
$libm_fn($($arg),*)
}
};
}
// verify-apilist-start
libm_helper! {
f32,
funcs: {
// verify-sorted-start
(fn acos(x: f32) -> (f32); => acosf);
(fn acosh(x: f32) -> (f32); => acoshf);
(fn asin(x: f32) -> (f32); => asinf);
(fn asinh(x: f32) -> (f32); => asinhf);
(fn atan(x: f32) -> (f32); => atanf);
(fn atan2(y: f32, x: f32) -> (f32); => atan2f);
(fn atanh(x: f32) -> (f32); => atanhf);
(fn cbrt(x: f32) -> (f32); => cbrtf);
(fn ceil(x: f32) -> (f32); => ceilf);
(fn copysign(x: f32, y: f32) -> (f32); => copysignf);
(fn cos(x: f32) -> (f32); => cosf);
(fn cosh(x: f32) -> (f32); => coshf);
(fn erf(x: f32) -> (f32); => erff);
(fn erfc(x: f32) -> (f32); => erfcf);
(fn exp(x: f32) -> (f32); => expf);
(fn exp10(x: f32) -> (f32); => exp10f);
(fn exp2(x: f32) -> (f32); => exp2f);
(fn expm1(x: f32) -> (f32); => expm1f);
(fn fabs(x: f32) -> (f32); => fabsf);
(fn fdim(x: f32, y: f32) -> (f32); => fdimf);
(fn floor(x: f32) -> (f32); => floorf);
(fn fma(x: f32, y: f32, z: f32) -> (f32); => fmaf);
(fn fmax(x: f32, y: f32) -> (f32); => fmaxf);
(fn fmin(x: f32, y: f32) -> (f32); => fminf);
(fn fmod(x: f32, y: f32) -> (f32); => fmodf);
(fn frexp(x: f32) -> (f32, i32); => frexpf);
(fn hypot(x: f32, y: f32) -> (f32); => hypotf);
(fn ilogb(x: f32) -> (i32); => ilogbf);
(fn j0(x: f32) -> (f32); => j0f);
(fn j1(x: f32) -> (f32); => j1f);
(fn jn(n: i32, x: f32) -> (f32); => jnf);
(fn ldexp(x: f32, n: i32) -> (f32); => ldexpf);
(fn lgamma(x: f32) -> (f32); => lgammaf);
(fn lgamma_r(x: f32) -> (f32, i32); => lgammaf_r);
(fn log(x: f32) -> (f32); => logf);
(fn log10(x: f32) -> (f32); => log10f);
(fn log1p(x: f32) -> (f32); => log1pf);
(fn log2(x: f32) -> (f32); => log2f);
(fn modf(x: f32) -> (f32, f32); => modff);
(fn nextafter(x: f32, y: f32) -> (f32); => nextafterf);
(fn pow(x: f32, y: f32) -> (f32); => powf);
(fn remainder(x: f32, y: f32) -> (f32); => remainderf);
(fn remquo(x: f32, y: f32) -> (f32, i32); => remquof);
(fn rint(x: f32) -> (f32); => rintf);
(fn round(x: f32) -> (f32); => roundf);
(fn roundeven(x: f32) -> (f32); => roundevenf);
(fn scalbn(x: f32, n: i32) -> (f32); => scalbnf);
(fn sin(x: f32) -> (f32); => sinf);
(fn sincos(x: f32) -> (f32, f32); => sincosf);
(fn sinh(x: f32) -> (f32); => sinhf);
(fn sqrt(x: f32) -> (f32); => sqrtf);
(fn tan(x: f32) -> (f32); => tanf);
(fn tanh(x: f32) -> (f32); => tanhf);
(fn tgamma(x: f32) -> (f32); => tgammaf);
(fn trunc(x: f32) -> (f32); => truncf);
(fn y0(x: f32) -> (f32); => y0f);
(fn y1(x: f32) -> (f32); => y1f);
(fn yn(n: i32, x: f32) -> (f32); => ynf);
// verify-sorted-end
}
}
libm_helper! {
f64,
funcs: {
// verify-sorted-start
(fn acos(x: f64) -> (f64); => acos);
(fn acosh(x: f64) -> (f64); => acosh);
(fn asin(x: f64) -> (f64); => asin);
(fn asinh(x: f64) -> (f64); => asinh);
(fn atan(x: f64) -> (f64); => atan);
(fn atan2(y: f64, x: f64) -> (f64); => atan2);
(fn atanh(x: f64) -> (f64); => atanh);
(fn cbrt(x: f64) -> (f64); => cbrt);
(fn ceil(x: f64) -> (f64); => ceil);
(fn copysign(x: f64, y: f64) -> (f64); => copysign);
(fn cos(x: f64) -> (f64); => cos);
(fn cosh(x: f64) -> (f64); => cosh);
(fn erf(x: f64) -> (f64); => erf);
(fn erfc(x: f64) -> (f64); => erfc);
(fn exp(x: f64) -> (f64); => exp);
(fn exp10(x: f64) -> (f64); => exp10);
(fn exp2(x: f64) -> (f64); => exp2);
(fn expm1(x: f64) -> (f64); => expm1);
(fn fabs(x: f64) -> (f64); => fabs);
(fn fdim(x: f64, y: f64) -> (f64); => fdim);
(fn floor(x: f64) -> (f64); => floor);
(fn fma(x: f64, y: f64, z: f64) -> (f64); => fma);
(fn fmax(x: f64, y: f64) -> (f64); => fmax);
(fn fmaximum(x: f64, y: f64) -> (f64); => fmaximum);
(fn fmaximum_num(x: f64, y: f64) -> (f64); => fmaximum_num);
(fn fmaximum_numf(x: f32, y: f32) -> (f32); => fmaximum_numf);
(fn fmaximumf(x: f32, y: f32) -> (f32); => fmaximumf);
(fn fmin(x: f64, y: f64) -> (f64); => fmin);
(fn fminimum(x: f64, y: f64) -> (f64); => fminimum);
(fn fminimum_num(x: f64, y: f64) -> (f64); => fminimum_num);
(fn fminimum_numf(x: f32, y: f32) -> (f32); => fminimum_numf);
(fn fminimumf(x: f32, y: f32) -> (f32); => fminimumf);
(fn fmod(x: f64, y: f64) -> (f64); => fmod);
(fn frexp(x: f64) -> (f64, i32); => frexp);
(fn hypot(x: f64, y: f64) -> (f64); => hypot);
(fn ilogb(x: f64) -> (i32); => ilogb);
(fn j0(x: f64) -> (f64); => j0);
(fn j1(x: f64) -> (f64); => j1);
(fn jn(n: i32, x: f64) -> (f64); => jn);
(fn ldexp(x: f64, n: i32) -> (f64); => ldexp);
(fn lgamma(x: f64) -> (f64); => lgamma);
(fn lgamma_r(x: f64) -> (f64, i32); => lgamma_r);
(fn log(x: f64) -> (f64); => log);
(fn log10(x: f64) -> (f64); => log10);
(fn log1p(x: f64) -> (f64); => log1p);
(fn log2(x: f64) -> (f64); => log2);
(fn modf(x: f64) -> (f64, f64); => modf);
(fn nextafter(x: f64, y: f64) -> (f64); => nextafter);
(fn pow(x: f64, y: f64) -> (f64); => pow);
(fn remainder(x: f64, y: f64) -> (f64); => remainder);
(fn remquo(x: f64, y: f64) -> (f64, i32); => remquo);
(fn rint(x: f64) -> (f64); => rint);
(fn round(x: f64) -> (f64); => round);
(fn roundevem(x: f64) -> (f64); => roundeven);
(fn scalbn(x: f64, n: i32) -> (f64); => scalbn);
(fn sin(x: f64) -> (f64); => sin);
(fn sincos(x: f64) -> (f64, f64); => sincos);
(fn sinh(x: f64) -> (f64); => sinh);
(fn sqrt(x: f64) -> (f64); => sqrt);
(fn tan(x: f64) -> (f64); => tan);
(fn tanh(x: f64) -> (f64); => tanh);
(fn tgamma(x: f64) -> (f64); => tgamma);
(fn trunc(x: f64) -> (f64); => trunc);
(fn y0(x: f64) -> (f64); => y0);
(fn y1(x: f64) -> (f64); => y1);
(fn yn(n: i32, x: f64) -> (f64); => yn);
// verify-sorted-end
}
}
#[cfg(f16_enabled)]
libm_helper! {
f16,
funcs: {
// verify-sorted-start
(fn ceil(x: f16) -> (f16); => ceilf16);
(fn copysign(x: f16, y: f16) -> (f16); => copysignf16);
(fn fabs(x: f16) -> (f16); => fabsf16);
(fn fdim(x: f16, y: f16) -> (f16); => fdimf16);
(fn floor(x: f16) -> (f16); => floorf16);
(fn fmax(x: f16, y: f16) -> (f16); => fmaxf16);
(fn fmaximum_num(x: f16, y: f16) -> (f16); => fmaximum_numf16);
(fn fmaximumf16(x: f16, y: f16) -> (f16); => fmaximumf16);
(fn fmin(x: f16, y: f16) -> (f16); => fminf16);
(fn fminimum(x: f16, y: f16) -> (f16); => fminimumf16);
(fn fminimum_num(x: f16, y: f16) -> (f16); => fminimum_numf16);
(fn fmod(x: f16, y: f16) -> (f16); => fmodf16);
(fn ldexp(x: f16, n: i32) -> (f16); => ldexpf16);
(fn rint(x: f16) -> (f16); => rintf16);
(fn round(x: f16) -> (f16); => roundf16);
(fn roundeven(x: f16) -> (f16); => roundevenf16);
(fn scalbn(x: f16, n: i32) -> (f16); => scalbnf16);
(fn sqrtf(x: f16) -> (f16); => sqrtf16);
(fn truncf(x: f16) -> (f16); => truncf16);
// verify-sorted-end
}
}
#[cfg(f128_enabled)]
libm_helper! {
f128,
funcs: {
// verify-sorted-start
(fn ceil(x: f128) -> (f128); => ceilf128);
(fn copysign(x: f128, y: f128) -> (f128); => copysignf128);
(fn fabs(x: f128) -> (f128); => fabsf128);
(fn fdim(x: f128, y: f128) -> (f128); => fdimf128);
(fn floor(x: f128) -> (f128); => floorf128);
(fn fma(x: f128, y: f128, z: f128) -> (f128); => fmaf128);
(fn fmax(x: f128, y: f128) -> (f128); => fmaxf128);
(fn fmaximum(x: f128, y: f128) -> (f128); => fmaximumf128);
(fn fmaximum_num(x: f128, y: f128) -> (f128); => fmaximum_numf128);
(fn fmin(x: f128, y: f128) -> (f128); => fminf128);
(fn fminimum(x: f128, y: f128) -> (f128); => fminimumf128);
(fn fminimum_num(x: f128, y: f128) -> (f128); => fminimum_numf128);
(fn fmod(x: f128, y: f128) -> (f128); => fmodf128);
(fn ldexp(x: f128, n: i32) -> (f128); => ldexpf128);
(fn rint(x: f128) -> (f128); => rintf128);
(fn round(x: f128) -> (f128); => roundf128);
(fn roundeven(x: f128) -> (f128); => roundevenf128);
(fn scalbn(x: f128, n: i32) -> (f128); => scalbnf128);
(fn sqrt(x: f128) -> (f128); => sqrtf128);
(fn trunc(x: f128) -> (f128); => truncf128);
// verify-sorted-end
}
}
// verify-apilist-end

112
vendor/libm/src/math/acos.rs vendored Normal file
View File

@@ -0,0 +1,112 @@
/* origin: FreeBSD /usr/src/lib/msun/src/e_acos.c */
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunSoft, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
/* acos(x)
* Method :
* acos(x) = pi/2 - asin(x)
* acos(-x) = pi/2 + asin(x)
* For |x|<=0.5
* acos(x) = pi/2 - (x + x*x^2*R(x^2)) (see asin.c)
* For x>0.5
* acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2)))
* = 2asin(sqrt((1-x)/2))
* = 2s + 2s*z*R(z) ...z=(1-x)/2, s=sqrt(z)
* = 2f + (2c + 2s*z*R(z))
* where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term
* for f so that f+c ~ sqrt(z).
* For x<-0.5
* acos(x) = pi - 2asin(sqrt((1-|x|)/2))
* = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z)
*
* Special cases:
* if x is NaN, return x itself;
* if |x|>1, return NaN with invalid signal.
*
* Function needed: sqrt
*/
use super::sqrt;
const PIO2_HI: f64 = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */
const PIO2_LO: f64 = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */
const PS0: f64 = 1.66666666666666657415e-01; /* 0x3FC55555, 0x55555555 */
const PS1: f64 = -3.25565818622400915405e-01; /* 0xBFD4D612, 0x03EB6F7D */
const PS2: f64 = 2.01212532134862925881e-01; /* 0x3FC9C155, 0x0E884455 */
const PS3: f64 = -4.00555345006794114027e-02; /* 0xBFA48228, 0xB5688F3B */
const PS4: f64 = 7.91534994289814532176e-04; /* 0x3F49EFE0, 0x7501B288 */
const PS5: f64 = 3.47933107596021167570e-05; /* 0x3F023DE1, 0x0DFDF709 */
const QS1: f64 = -2.40339491173441421878e+00; /* 0xC0033A27, 0x1C8A2D4B */
const QS2: f64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */
const QS3: f64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */
const QS4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
fn r(z: f64) -> f64 {
let p: f64 = z * (PS0 + z * (PS1 + z * (PS2 + z * (PS3 + z * (PS4 + z * PS5)))));
let q: f64 = 1.0 + z * (QS1 + z * (QS2 + z * (QS3 + z * QS4)));
p / q
}
/// Arccosine (f64)
///
/// Computes the inverse cosine (arc cosine) of the input value.
/// Arguments must be in the range -1 to 1.
/// Returns values in radians, in the range of 0 to pi.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn acos(x: f64) -> f64 {
let x1p_120f = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ -120
let z: f64;
let w: f64;
let s: f64;
let c: f64;
let df: f64;
let hx: u32;
let ix: u32;
hx = (x.to_bits() >> 32) as u32;
ix = hx & 0x7fffffff;
/* |x| >= 1 or nan */
if ix >= 0x3ff00000 {
let lx: u32 = x.to_bits() as u32;
if ((ix - 0x3ff00000) | lx) == 0 {
/* acos(1)=0, acos(-1)=pi */
if (hx >> 31) != 0 {
return 2. * PIO2_HI + x1p_120f;
}
return 0.;
}
return 0. / (x - x);
}
/* |x| < 0.5 */
if ix < 0x3fe00000 {
if ix <= 0x3c600000 {
/* |x| < 2**-57 */
return PIO2_HI + x1p_120f;
}
return PIO2_HI - (x - (PIO2_LO - x * r(x * x)));
}
/* x < -0.5 */
if (hx >> 31) != 0 {
z = (1.0 + x) * 0.5;
s = sqrt(z);
w = r(z) * s - PIO2_LO;
return 2. * (PIO2_HI - (s + w));
}
/* x > 0.5 */
z = (1.0 - x) * 0.5;
s = sqrt(z);
// Set the low 4 bytes to zero
df = f64::from_bits(s.to_bits() & 0xff_ff_ff_ff_00_00_00_00);
c = (z - df * df) / (s + df);
w = r(z) * s + c;
2. * (df + w)
}

79
vendor/libm/src/math/acosf.rs vendored Normal file
View File

@@ -0,0 +1,79 @@
/* origin: FreeBSD /usr/src/lib/msun/src/e_acosf.c */
/*
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
use super::sqrt::sqrtf;
const PIO2_HI: f32 = 1.5707962513e+00; /* 0x3fc90fda */
const PIO2_LO: f32 = 7.5497894159e-08; /* 0x33a22168 */
const P_S0: f32 = 1.6666586697e-01;
const P_S1: f32 = -4.2743422091e-02;
const P_S2: f32 = -8.6563630030e-03;
const Q_S1: f32 = -7.0662963390e-01;
fn r(z: f32) -> f32 {
let p = z * (P_S0 + z * (P_S1 + z * P_S2));
let q = 1. + z * Q_S1;
p / q
}
/// Arccosine (f32)
///
/// Computes the inverse cosine (arc cosine) of the input value.
/// Arguments must be in the range -1 to 1.
/// Returns values in radians, in the range of 0 to pi.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn acosf(x: f32) -> f32 {
let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120)
let z: f32;
let w: f32;
let s: f32;
let mut hx = x.to_bits();
let ix = hx & 0x7fffffff;
/* |x| >= 1 or nan */
if ix >= 0x3f800000 {
if ix == 0x3f800000 {
if (hx >> 31) != 0 {
return 2. * PIO2_HI + x1p_120;
}
return 0.;
}
return 0. / (x - x);
}
/* |x| < 0.5 */
if ix < 0x3f000000 {
if ix <= 0x32800000 {
/* |x| < 2**-26 */
return PIO2_HI + x1p_120;
}
return PIO2_HI - (x - (PIO2_LO - x * r(x * x)));
}
/* x < -0.5 */
if (hx >> 31) != 0 {
z = (1. + x) * 0.5;
s = sqrtf(z);
w = r(z) * s - PIO2_LO;
return 2. * (PIO2_HI - (s + w));
}
/* x > 0.5 */
z = (1. - x) * 0.5;
s = sqrtf(z);
hx = s.to_bits();
let df = f32::from_bits(hx & 0xfffff000);
let c = (z - df * df) / (s + df);
w = r(z) * s + c;
2. * (df + w)
}

27
vendor/libm/src/math/acosh.rs vendored Normal file
View File

@@ -0,0 +1,27 @@
use super::{log, log1p, sqrt};
const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/
/// Inverse hyperbolic cosine (f64)
///
/// Calculates the inverse hyperbolic cosine of `x`.
/// Is defined as `log(x + sqrt(x*x-1))`.
/// `x` must be a number greater than or equal to 1.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn acosh(x: f64) -> f64 {
let u = x.to_bits();
let e = ((u >> 52) as usize) & 0x7ff;
/* x < 1 domain error is handled in the called functions */
if e < 0x3ff + 1 {
/* |x| < 2, up to 2ulp error in [1,1.125] */
return log1p(x - 1.0 + sqrt((x - 1.0) * (x - 1.0) + 2.0 * (x - 1.0)));
}
if e < 0x3ff + 26 {
/* |x| < 0x1p26 */
return log(2.0 * x - 1.0 / (x + sqrt(x * x - 1.0)));
}
/* |x| >= 0x1p26 or nan */
return log(x) + LN2;
}

26
vendor/libm/src/math/acoshf.rs vendored Normal file
View File

@@ -0,0 +1,26 @@
use super::{log1pf, logf, sqrtf};
const LN2: f32 = 0.693147180559945309417232121458176568;
/// Inverse hyperbolic cosine (f32)
///
/// Calculates the inverse hyperbolic cosine of `x`.
/// Is defined as `log(x + sqrt(x*x-1))`.
/// `x` must be a number greater than or equal to 1.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn acoshf(x: f32) -> f32 {
let u = x.to_bits();
let a = u & 0x7fffffff;
if a < 0x3f800000 + (1 << 23) {
/* |x| < 2, invalid if x < 1 or nan */
/* up to 2ulp error in [1,1.125] */
return log1pf(x - 1.0 + sqrtf((x - 1.0) * (x - 1.0) + 2.0 * (x - 1.0)));
}
if a < 0x3f800000 + (12 << 23) {
/* |x| < 0x1p12 */
return logf(2.0 * x - 1.0 / (x + sqrtf(x * x - 1.0)));
}
/* x >= 0x1p12 */
return logf(x) + LN2;
}

115
vendor/libm/src/math/arch/aarch64.rs vendored Normal file
View File

@@ -0,0 +1,115 @@
//! Architecture-specific support for aarch64 with neon.
use core::arch::asm;
pub fn fma(mut x: f64, y: f64, z: f64) -> f64 {
// SAFETY: `fmadd` is available with neon and has no side effects.
unsafe {
asm!(
"fmadd {x:d}, {x:d}, {y:d}, {z:d}",
x = inout(vreg) x,
y = in(vreg) y,
z = in(vreg) z,
options(nomem, nostack, pure)
);
}
x
}
pub fn fmaf(mut x: f32, y: f32, z: f32) -> f32 {
// SAFETY: `fmadd` is available with neon and has no side effects.
unsafe {
asm!(
"fmadd {x:s}, {x:s}, {y:s}, {z:s}",
x = inout(vreg) x,
y = in(vreg) y,
z = in(vreg) z,
options(nomem, nostack, pure)
);
}
x
}
pub fn rint(mut x: f64) -> f64 {
// SAFETY: `frintn` is available with neon and has no side effects.
//
// `frintn` is always round-to-nearest which does not match the C specification, but Rust does
// not support rounding modes.
unsafe {
asm!(
"frintn {x:d}, {x:d}",
x = inout(vreg) x,
options(nomem, nostack, pure)
);
}
x
}
pub fn rintf(mut x: f32) -> f32 {
// SAFETY: `frintn` is available with neon and has no side effects.
//
// `frintn` is always round-to-nearest which does not match the C specification, but Rust does
// not support rounding modes.
unsafe {
asm!(
"frintn {x:s}, {x:s}",
x = inout(vreg) x,
options(nomem, nostack, pure)
);
}
x
}
#[cfg(all(f16_enabled, target_feature = "fp16"))]
pub fn rintf16(mut x: f16) -> f16 {
// SAFETY: `frintn` is available for `f16` with `fp16` (implies `neon`) and has no side effects.
//
// `frintn` is always round-to-nearest which does not match the C specification, but Rust does
// not support rounding modes.
unsafe {
asm!(
"frintn {x:h}, {x:h}",
x = inout(vreg) x,
options(nomem, nostack, pure)
);
}
x
}
pub fn sqrt(mut x: f64) -> f64 {
// SAFETY: `fsqrt` is available with neon and has no side effects.
unsafe {
asm!(
"fsqrt {x:d}, {x:d}",
x = inout(vreg) x,
options(nomem, nostack, pure)
);
}
x
}
pub fn sqrtf(mut x: f32) -> f32 {
// SAFETY: `fsqrt` is available with neon and has no side effects.
unsafe {
asm!(
"fsqrt {x:s}, {x:s}",
x = inout(vreg) x,
options(nomem, nostack, pure)
);
}
x
}
#[cfg(all(f16_enabled, target_feature = "fp16"))]
pub fn sqrtf16(mut x: f16) -> f16 {
// SAFETY: `fsqrt` is available for `f16` with `fp16` (implies `neon`) and has no
// side effects.
unsafe {
asm!(
"fsqrt {x:h}, {x:h}",
x = inout(vreg) x,
options(nomem, nostack, pure)
);
}
x
}

37
vendor/libm/src/math/arch/i586.rs vendored Normal file
View File

@@ -0,0 +1,37 @@
//! Architecture-specific support for x86-32 without SSE2
use super::super::fabs;
/// Use an alternative implementation on x86, because the
/// main implementation fails with the x87 FPU used by
/// debian i386, probably due to excess precision issues.
/// Basic implementation taken from https://github.com/rust-lang/libm/issues/219.
pub fn ceil(x: f64) -> f64 {
if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() {
let truncated = x as i64 as f64;
if truncated < x {
return truncated + 1.0;
} else {
return truncated;
}
} else {
return x;
}
}
/// Use an alternative implementation on x86, because the
/// main implementation fails with the x87 FPU used by
/// debian i386, probably due to excess precision issues.
/// Basic implementation taken from https://github.com/rust-lang/libm/issues/219.
pub fn floor(x: f64) -> f64 {
if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() {
let truncated = x as i64 as f64;
if truncated > x {
return truncated - 1.0;
} else {
return truncated;
}
} else {
return x;
}
}

50
vendor/libm/src/math/arch/mod.rs vendored Normal file
View File

@@ -0,0 +1,50 @@
//! Architecture-specific routines and operations.
//!
//! LLVM will already optimize calls to some of these in cases that there are hardware
//! instructions. Providing an implementation here just ensures that the faster implementation
//! is used when calling the function directly. This helps anyone who uses `libm` directly, as
//! well as improving things when these routines are called as part of other implementations.
// Most implementations should be defined here, to ensure they are not made available when
// soft floats are required.
#[cfg(arch_enabled)]
cfg_if! {
if #[cfg(all(target_arch = "wasm32", intrinsics_enabled))] {
mod wasm32;
pub use wasm32::{
ceil, ceilf, fabs, fabsf, floor, floorf, rint, rintf, sqrt, sqrtf, trunc, truncf,
};
} else if #[cfg(target_feature = "sse2")] {
mod x86;
pub use x86::{sqrt, sqrtf, fma, fmaf};
} else if #[cfg(all(
any(target_arch = "aarch64", target_arch = "arm64ec"),
target_feature = "neon"
))] {
mod aarch64;
pub use aarch64::{
fma,
fmaf,
rint,
rintf,
sqrt,
sqrtf,
};
#[cfg(all(f16_enabled, target_feature = "fp16"))]
pub use aarch64::{
rintf16,
sqrtf16,
};
}
}
// There are certain architecture-specific implementations that are needed for correctness
// even with `force-soft-float`. These are configured here.
cfg_if! {
if #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] {
mod i586;
pub use i586::{ceil, floor};
}
}

50
vendor/libm/src/math/arch/wasm32.rs vendored Normal file
View File

@@ -0,0 +1,50 @@
//! Wasm has builtins for simple float operations. Use the unstable `core::arch` intrinsics which
//! are significantly faster than soft float operations.
pub fn ceil(x: f64) -> f64 {
core::arch::wasm32::f64_ceil(x)
}
pub fn ceilf(x: f32) -> f32 {
core::arch::wasm32::f32_ceil(x)
}
pub fn fabs(x: f64) -> f64 {
x.abs()
}
pub fn fabsf(x: f32) -> f32 {
x.abs()
}
pub fn floor(x: f64) -> f64 {
core::arch::wasm32::f64_floor(x)
}
pub fn floorf(x: f32) -> f32 {
core::arch::wasm32::f32_floor(x)
}
pub fn rint(x: f64) -> f64 {
core::arch::wasm32::f64_nearest(x)
}
pub fn rintf(x: f32) -> f32 {
core::arch::wasm32::f32_nearest(x)
}
pub fn sqrt(x: f64) -> f64 {
core::arch::wasm32::f64_sqrt(x)
}
pub fn sqrtf(x: f32) -> f32 {
core::arch::wasm32::f32_sqrt(x)
}
pub fn trunc(x: f64) -> f64 {
core::arch::wasm32::f64_trunc(x)
}
pub fn truncf(x: f32) -> f32 {
core::arch::wasm32::f32_trunc(x)
}

32
vendor/libm/src/math/arch/x86.rs vendored Normal file
View File

@@ -0,0 +1,32 @@
//! Architecture-specific support for x86-32 and x86-64 with SSE2
mod detect;
mod fma;
pub use fma::{fma, fmaf};
pub fn sqrtf(mut x: f32) -> f32 {
// SAFETY: `sqrtss` is part of `sse2`, which this module is gated behind. It has no memory
// access or side effects.
unsafe {
core::arch::asm!(
"sqrtss {x}, {x}",
x = inout(xmm_reg) x,
options(nostack, nomem, pure),
)
};
x
}
pub fn sqrt(mut x: f64) -> f64 {
// SAFETY: `sqrtsd` is part of `sse2`, which this module is gated behind. It has no memory
// access or side effects.
unsafe {
core::arch::asm!(
"sqrtsd {x}, {x}",
x = inout(xmm_reg) x,
options(nostack, nomem, pure),
)
};
x
}

232
vendor/libm/src/math/arch/x86/detect.rs vendored Normal file
View File

@@ -0,0 +1,232 @@
// Using runtime feature detection requires atomics. Currently there are no x86 targets
// that support sse but not `AtomicPtr`.
#[cfg(target_arch = "x86")]
use core::arch::x86::{__cpuid, __cpuid_count, _xgetbv, CpuidResult};
#[cfg(target_arch = "x86_64")]
use core::arch::x86_64::{__cpuid, __cpuid_count, _xgetbv, CpuidResult};
use crate::support::feature_detect::{Flags, get_or_init_flags_cache, unique_masks};
/// CPU features that get cached (doesn't correlate to anything on the CPU).
pub mod cpu_flags {
use super::unique_masks;
unique_masks! {
u32,
SSE3,
F16C,
SSE,
SSE2,
ERMSB,
MOVRS,
FMA,
FMA4,
AVX512FP16,
AVX512BF16,
}
}
/// Get CPU features, loading from a cache if available.
pub fn get_cpu_features() -> Flags {
use core::sync::atomic::AtomicU32;
static CACHE: AtomicU32 = AtomicU32::new(0);
get_or_init_flags_cache(&CACHE, load_x86_features)
}
/// Read from cpuid and translate to a `Flags` instance, using `cpu_flags`.
///
/// Implementation is taken from [std-detect][std-detect].
///
/// [std-detect]: https://github.com/rust-lang/stdarch/blob/690b3a6334d482874163bd6fcef408e0518febe9/crates/std_detect/src/detect/os/x86.rs#L142
fn load_x86_features() -> Flags {
let mut value = Flags::empty();
if cfg!(target_env = "sgx") {
// doesn't support this because it is untrusted data
return Flags::empty();
}
// Calling `__cpuid`/`__cpuid_count` from here on is safe because the CPU
// has `cpuid` support.
// 0. EAX = 0: Basic Information:
// - EAX returns the "Highest Function Parameter", that is, the maximum leaf
// value for subsequent calls of `cpuinfo` in range [0, 0x8000_0000].
// - The vendor ID is stored in 12 u8 ascii chars, returned in EBX, EDX, and ECX
// (in that order)
let mut vendor_id = [0u8; 12];
let max_basic_leaf;
unsafe {
let CpuidResult { eax, ebx, ecx, edx } = __cpuid(0);
max_basic_leaf = eax;
vendor_id[0..4].copy_from_slice(&ebx.to_ne_bytes());
vendor_id[4..8].copy_from_slice(&edx.to_ne_bytes());
vendor_id[8..12].copy_from_slice(&ecx.to_ne_bytes());
}
if max_basic_leaf < 1 {
// Earlier Intel 486, CPUID not implemented
return value;
}
// EAX = 1, ECX = 0: Queries "Processor Info and Feature Bits";
// Contains information about most x86 features.
let CpuidResult { ecx, edx, .. } = unsafe { __cpuid(0x0000_0001_u32) };
let proc_info_ecx = Flags::from_bits(ecx);
let proc_info_edx = Flags::from_bits(edx);
// EAX = 7: Queries "Extended Features";
// Contains information about bmi,bmi2, and avx2 support.
let mut extended_features_ebx = Flags::empty();
let mut extended_features_edx = Flags::empty();
let mut extended_features_eax_leaf_1 = Flags::empty();
if max_basic_leaf >= 7 {
let CpuidResult { ebx, edx, .. } = unsafe { __cpuid(0x0000_0007_u32) };
extended_features_ebx = Flags::from_bits(ebx);
extended_features_edx = Flags::from_bits(edx);
let CpuidResult { eax, .. } = unsafe { __cpuid_count(0x0000_0007_u32, 0x0000_0001_u32) };
extended_features_eax_leaf_1 = Flags::from_bits(eax)
}
// EAX = 0x8000_0000, ECX = 0: Get Highest Extended Function Supported
// - EAX returns the max leaf value for extended information, that is,
// `cpuid` calls in range [0x8000_0000; u32::MAX]:
let extended_max_basic_leaf = unsafe { __cpuid(0x8000_0000_u32) }.eax;
// EAX = 0x8000_0001, ECX=0: Queries "Extended Processor Info and Feature Bits"
let mut extended_proc_info_ecx = Flags::empty();
if extended_max_basic_leaf >= 1 {
let CpuidResult { ecx, .. } = unsafe { __cpuid(0x8000_0001_u32) };
extended_proc_info_ecx = Flags::from_bits(ecx);
}
let mut enable = |regflags: Flags, regbit, flag| {
if regflags.test_nth(regbit) {
value.insert(flag);
}
};
enable(proc_info_ecx, 0, cpu_flags::SSE3);
enable(proc_info_ecx, 29, cpu_flags::F16C);
enable(proc_info_edx, 25, cpu_flags::SSE);
enable(proc_info_edx, 26, cpu_flags::SSE2);
enable(extended_features_ebx, 9, cpu_flags::ERMSB);
enable(extended_features_eax_leaf_1, 31, cpu_flags::MOVRS);
// `XSAVE` and `AVX` support:
let cpu_xsave = proc_info_ecx.test_nth(26);
if cpu_xsave {
// 0. Here the CPU supports `XSAVE`.
// 1. Detect `OSXSAVE`, that is, whether the OS is AVX enabled and
// supports saving the state of the AVX/AVX2 vector registers on
// context-switches, see:
//
// - [intel: is avx enabled?][is_avx_enabled],
// - [mozilla: sse.cpp][mozilla_sse_cpp].
//
// [is_avx_enabled]: https://software.intel.com/en-us/blogs/2011/04/14/is-avx-enabled
// [mozilla_sse_cpp]: https://hg.mozilla.org/mozilla-central/file/64bab5cbb9b6/mozglue/build/SSE.cpp#l190
let cpu_osxsave = proc_info_ecx.test_nth(27);
if cpu_osxsave {
// 2. The OS must have signaled the CPU that it supports saving and
// restoring the:
//
// * SSE -> `XCR0.SSE[1]`
// * AVX -> `XCR0.AVX[2]`
// * AVX-512 -> `XCR0.AVX-512[7:5]`.
// * AMX -> `XCR0.AMX[18:17]`
//
// by setting the corresponding bits of `XCR0` to `1`.
//
// This is safe because the CPU supports `xsave` and the OS has set `osxsave`.
let xcr0 = unsafe { _xgetbv(0) };
// Test `XCR0.SSE[1]` and `XCR0.AVX[2]` with the mask `0b110 == 6`:
let os_avx_support = xcr0 & 6 == 6;
// Test `XCR0.AVX-512[7:5]` with the mask `0b1110_0000 == 0xe0`:
let os_avx512_support = xcr0 & 0xe0 == 0xe0;
// Only if the OS and the CPU support saving/restoring the AVX
// registers we enable `xsave` support:
if os_avx_support {
// See "13.3 ENABLING THE XSAVE FEATURE SET AND XSAVE-ENABLED
// FEATURES" in the "Intel® 64 and IA-32 Architectures Software
// Developers Manual, Volume 1: Basic Architecture":
//
// "Software enables the XSAVE feature set by setting
// CR4.OSXSAVE[bit 18] to 1 (e.g., with the MOV to CR4
// instruction). If this bit is 0, execution of any of XGETBV,
// XRSTOR, XRSTORS, XSAVE, XSAVEC, XSAVEOPT, XSAVES, and XSETBV
// causes an invalid-opcode exception (#UD)"
// FMA (uses 256-bit wide registers):
enable(proc_info_ecx, 12, cpu_flags::FMA);
// For AVX-512 the OS also needs to support saving/restoring
// the extended state, only then we enable AVX-512 support:
if os_avx512_support {
enable(extended_features_edx, 23, cpu_flags::AVX512FP16);
enable(extended_features_eax_leaf_1, 5, cpu_flags::AVX512BF16);
}
}
}
}
// As Hygon Dhyana originates from AMD technology and shares most of the architecture with
// AMD's family 17h, but with different CPU Vendor ID("HygonGenuine")/Family series number
// (Family 18h).
//
// For CPUID feature bits, Hygon Dhyana(family 18h) share the same definition with AMD
// family 17h.
//
// Related AMD CPUID specification is https://www.amd.com/system/files/TechDocs/25481.pdf
// (AMD64 Architecture Programmer's Manual, Appendix E).
// Related Hygon kernel patch can be found on
// http://lkml.kernel.org/r/5ce86123a7b9dad925ac583d88d2f921040e859b.1538583282.git.puwen@hygon.cn
if vendor_id == *b"AuthenticAMD" || vendor_id == *b"HygonGenuine" {
// These features are available on AMD arch CPUs:
enable(extended_proc_info_ecx, 16, cpu_flags::FMA4);
}
value
}
#[cfg(test)]
mod tests {
extern crate std;
use std::is_x86_feature_detected;
use super::*;
#[test]
fn check_matches_std() {
let features = get_cpu_features();
for i in 0..cpu_flags::ALL.len() {
let flag = cpu_flags::ALL[i];
let name = cpu_flags::NAMES[i];
let std_detected = match flag {
cpu_flags::SSE3 => is_x86_feature_detected!("sse3"),
cpu_flags::F16C => is_x86_feature_detected!("f16c"),
cpu_flags::SSE => is_x86_feature_detected!("sse"),
cpu_flags::SSE2 => is_x86_feature_detected!("sse2"),
cpu_flags::ERMSB => is_x86_feature_detected!("ermsb"),
cpu_flags::MOVRS => continue, // only very recent support in std
cpu_flags::FMA => is_x86_feature_detected!("fma"),
cpu_flags::FMA4 => continue, // not yet supported in std
cpu_flags::AVX512FP16 => is_x86_feature_detected!("avx512fp16"),
cpu_flags::AVX512BF16 => is_x86_feature_detected!("avx512bf16"),
_ => panic!("untested CPU flag {name}"),
};
assert_eq!(
std_detected,
features.contains(flag),
"different flag {name}. flags: {features:?}"
);
}
}
}

135
vendor/libm/src/math/arch/x86/fma.rs vendored Normal file
View File

@@ -0,0 +1,135 @@
//! Use assembly fma if the `fma` or `fma4` feature is detected at runtime.
use core::arch::asm;
use super::super::super::generic;
use super::detect::{cpu_flags, get_cpu_features};
use crate::support::Round;
use crate::support::feature_detect::select_once;
pub fn fma(x: f64, y: f64, z: f64) -> f64 {
select_once! {
sig: fn(x: f64, y: f64, z: f64) -> f64,
init: || {
let features = get_cpu_features();
if features.contains(cpu_flags::FMA) {
fma_with_fma
} else if features.contains(cpu_flags::FMA4) {
fma_with_fma4
} else {
fma_fallback as Func
}
},
// SAFETY: `fn_ptr` is the result of `init`, preconditions have been checked.
call: |fn_ptr: Func| unsafe { fn_ptr(x, y, z) },
}
}
pub fn fmaf(x: f32, y: f32, z: f32) -> f32 {
select_once! {
sig: fn(x: f32, y: f32, z: f32) -> f32,
init: || {
let features = get_cpu_features();
if features.contains(cpu_flags::FMA) {
fmaf_with_fma
} else if features.contains(cpu_flags::FMA4) {
fmaf_with_fma4
} else {
fmaf_fallback as Func
}
},
// SAFETY: `fn_ptr` is the result of `init`, preconditions have been checked.
call: |fn_ptr: Func| unsafe { fn_ptr(x, y, z) },
}
}
/// # Safety
///
/// Must have +fma available.
unsafe fn fma_with_fma(mut x: f64, y: f64, z: f64) -> f64 {
debug_assert!(get_cpu_features().contains(cpu_flags::FMA));
// SAFETY: fma is asserted available by precondition, which provides the instruction. No
// memory access or side effects.
unsafe {
asm!(
"vfmadd213sd {x}, {y}, {z}",
x = inout(xmm_reg) x,
y = in(xmm_reg) y,
z = in(xmm_reg) z,
options(nostack, nomem, pure),
);
}
x
}
/// # Safety
///
/// Must have +fma available.
unsafe fn fmaf_with_fma(mut x: f32, y: f32, z: f32) -> f32 {
debug_assert!(get_cpu_features().contains(cpu_flags::FMA));
// SAFETY: fma is asserted available by precondition, which provides the instruction. No
// memory access or side effects.
unsafe {
asm!(
"vfmadd213ss {x}, {y}, {z}",
x = inout(xmm_reg) x,
y = in(xmm_reg) y,
z = in(xmm_reg) z,
options(nostack, nomem, pure),
);
}
x
}
/// # Safety
///
/// Must have +fma4 available.
unsafe fn fma_with_fma4(mut x: f64, y: f64, z: f64) -> f64 {
debug_assert!(get_cpu_features().contains(cpu_flags::FMA4));
// SAFETY: fma4 is asserted available by precondition, which provides the instruction. No
// memory access or side effects.
unsafe {
asm!(
"vfmaddsd {x}, {x}, {y}, {z}",
x = inout(xmm_reg) x,
y = in(xmm_reg) y,
z = in(xmm_reg) z,
options(nostack, nomem, pure),
);
}
x
}
/// # Safety
///
/// Must have +fma4 available.
unsafe fn fmaf_with_fma4(mut x: f32, y: f32, z: f32) -> f32 {
debug_assert!(get_cpu_features().contains(cpu_flags::FMA4));
// SAFETY: fma4 is asserted available by precondition, which provides the instruction. No
// memory access or side effects.
unsafe {
asm!(
"vfmaddss {x}, {x}, {y}, {z}",
x = inout(xmm_reg) x,
y = in(xmm_reg) y,
z = in(xmm_reg) z,
options(nostack, nomem, pure),
);
}
x
}
// FIXME: the `select_implementation` macro should handle arch implementations that want
// to use the fallback, so we don't need to recreate the body.
fn fma_fallback(x: f64, y: f64, z: f64) -> f64 {
generic::fma_round(x, y, z, Round::Nearest).val
}
fn fmaf_fallback(x: f32, y: f32, z: f32) -> f32 {
generic::fma_wide_round(x, y, z, Round::Nearest).val
}

115
vendor/libm/src/math/asin.rs vendored Normal file
View File

@@ -0,0 +1,115 @@
/* origin: FreeBSD /usr/src/lib/msun/src/e_asin.c */
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunSoft, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
/* asin(x)
* Method :
* Since asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ...
* we approximate asin(x) on [0,0.5] by
* asin(x) = x + x*x^2*R(x^2)
* where
* R(x^2) is a rational approximation of (asin(x)-x)/x^3
* and its remez error is bounded by
* |(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75)
*
* For x in [0.5,1]
* asin(x) = pi/2-2*asin(sqrt((1-x)/2))
* Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2;
* then for x>0.98
* asin(x) = pi/2 - 2*(s+s*z*R(z))
* = pio2_hi - (2*(s+s*z*R(z)) - pio2_lo)
* For x<=0.98, let pio4_hi = pio2_hi/2, then
* f = hi part of s;
* c = sqrt(z) - f = (z-f*f)/(s+f) ...f+c=sqrt(z)
* and
* asin(x) = pi/2 - 2*(s+s*z*R(z))
* = pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo)
* = pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c))
*
* Special cases:
* if x is NaN, return x itself;
* if |x|>1, return NaN with invalid signal.
*
*/
use super::{fabs, get_high_word, get_low_word, sqrt, with_set_low_word};
const PIO2_HI: f64 = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */
const PIO2_LO: f64 = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */
/* coefficients for R(x^2) */
const P_S0: f64 = 1.66666666666666657415e-01; /* 0x3FC55555, 0x55555555 */
const P_S1: f64 = -3.25565818622400915405e-01; /* 0xBFD4D612, 0x03EB6F7D */
const P_S2: f64 = 2.01212532134862925881e-01; /* 0x3FC9C155, 0x0E884455 */
const P_S3: f64 = -4.00555345006794114027e-02; /* 0xBFA48228, 0xB5688F3B */
const P_S4: f64 = 7.91534994289814532176e-04; /* 0x3F49EFE0, 0x7501B288 */
const P_S5: f64 = 3.47933107596021167570e-05; /* 0x3F023DE1, 0x0DFDF709 */
const Q_S1: f64 = -2.40339491173441421878e+00; /* 0xC0033A27, 0x1C8A2D4B */
const Q_S2: f64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */
const Q_S3: f64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */
const Q_S4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
fn comp_r(z: f64) -> f64 {
let p = z * (P_S0 + z * (P_S1 + z * (P_S2 + z * (P_S3 + z * (P_S4 + z * P_S5)))));
let q = 1.0 + z * (Q_S1 + z * (Q_S2 + z * (Q_S3 + z * Q_S4)));
p / q
}
/// Arcsine (f64)
///
/// Computes the inverse sine (arc sine) of the argument `x`.
/// Arguments to asin must be in the range -1 to 1.
/// Returns values in radians, in the range of -pi/2 to pi/2.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn asin(mut x: f64) -> f64 {
let z: f64;
let r: f64;
let s: f64;
let hx: u32;
let ix: u32;
hx = get_high_word(x);
ix = hx & 0x7fffffff;
/* |x| >= 1 or nan */
if ix >= 0x3ff00000 {
let lx: u32;
lx = get_low_word(x);
if ((ix - 0x3ff00000) | lx) == 0 {
/* asin(1) = +-pi/2 with inexact */
return x * PIO2_HI + f64::from_bits(0x3870000000000000);
} else {
return 0.0 / (x - x);
}
}
/* |x| < 0.5 */
if ix < 0x3fe00000 {
/* if 0x1p-1022 <= |x| < 0x1p-26, avoid raising underflow */
if (0x00100000..0x3e500000).contains(&ix) {
return x;
} else {
return x + x * comp_r(x * x);
}
}
/* 1 > |x| >= 0.5 */
z = (1.0 - fabs(x)) * 0.5;
s = sqrt(z);
r = comp_r(z);
if ix >= 0x3fef3333 {
/* if |x| > 0.975 */
x = PIO2_HI - (2. * (s + s * r) - PIO2_LO);
} else {
let f: f64;
let c: f64;
/* f+c = sqrt(z) */
f = with_set_low_word(s, 0);
c = (z - f * f) / (s + f);
x = 0.5 * PIO2_HI - (2.0 * s * r - (PIO2_LO - 2.0 * c) - (0.5 * PIO2_HI - 2.0 * f));
}
if hx >> 31 != 0 { -x } else { x }
}

68
vendor/libm/src/math/asinf.rs vendored Normal file
View File

@@ -0,0 +1,68 @@
/* origin: FreeBSD /usr/src/lib/msun/src/e_asinf.c */
/*
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
use super::sqrt::sqrt;
use super::support::Float;
const PIO2: f64 = 1.570796326794896558e+00;
/* coefficients for R(x^2) */
const P_S0: f32 = 1.6666586697e-01;
const P_S1: f32 = -4.2743422091e-02;
const P_S2: f32 = -8.6563630030e-03;
const Q_S1: f32 = -7.0662963390e-01;
fn r(z: f32) -> f32 {
let p = z * (P_S0 + z * (P_S1 + z * P_S2));
let q = 1. + z * Q_S1;
p / q
}
/// Arcsine (f32)
///
/// Computes the inverse sine (arc sine) of the argument `x`.
/// Arguments to asin must be in the range -1 to 1.
/// Returns values in radians, in the range of -pi/2 to pi/2.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn asinf(mut x: f32) -> f32 {
let x1p_120 = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ (-120)
let hx = x.to_bits();
let ix = hx & 0x7fffffff;
if ix >= 0x3f800000 {
/* |x| >= 1 */
if ix == 0x3f800000 {
/* |x| == 1 */
return ((x as f64) * PIO2 + x1p_120) as f32; /* asin(+-1) = +-pi/2 with inexact */
}
return 0. / (x - x); /* asin(|x|>1) is NaN */
}
if ix < 0x3f000000 {
/* |x| < 0.5 */
/* if 0x1p-126 <= |x| < 0x1p-12, avoid raising underflow */
if (0x00800000..0x39800000).contains(&ix) {
return x;
}
return x + x * r(x * x);
}
/* 1 > |x| >= 0.5 */
let z = (1. - Float::abs(x)) * 0.5;
let s = sqrt(z as f64);
x = (PIO2 - 2. * (s + s * (r(z) as f64))) as f32;
if (hx >> 31) != 0 { -x } else { x }
}

36
vendor/libm/src/math/asinh.rs vendored Normal file
View File

@@ -0,0 +1,36 @@
use super::{log, log1p, sqrt};
const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/
/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */
/// Inverse hyperbolic sine (f64)
///
/// Calculates the inverse hyperbolic sine of `x`.
/// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn asinh(mut x: f64) -> f64 {
let mut u = x.to_bits();
let e = ((u >> 52) as usize) & 0x7ff;
let sign = (u >> 63) != 0;
/* |x| */
u &= (!0) >> 1;
x = f64::from_bits(u);
if e >= 0x3ff + 26 {
/* |x| >= 0x1p26 or inf or nan */
x = log(x) + LN2;
} else if e >= 0x3ff + 1 {
/* |x| >= 2 */
x = log(2.0 * x + 1.0 / (sqrt(x * x + 1.0) + x));
} else if e >= 0x3ff - 26 {
/* |x| >= 0x1p-26, up to 1.6ulp error in [0.125,0.5] */
x = log1p(x + x * x / (sqrt(x * x + 1.0) + 1.0));
} else {
/* |x| < 0x1p-26, raise inexact if x != 0 */
let x1p120 = f64::from_bits(0x4770000000000000);
force_eval!(x + x1p120);
}
if sign { -x } else { x }
}

35
vendor/libm/src/math/asinhf.rs vendored Normal file
View File

@@ -0,0 +1,35 @@
use super::{log1pf, logf, sqrtf};
const LN2: f32 = 0.693147180559945309417232121458176568;
/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */
/// Inverse hyperbolic sine (f32)
///
/// Calculates the inverse hyperbolic sine of `x`.
/// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn asinhf(mut x: f32) -> f32 {
let u = x.to_bits();
let i = u & 0x7fffffff;
let sign = (u >> 31) != 0;
/* |x| */
x = f32::from_bits(i);
if i >= 0x3f800000 + (12 << 23) {
/* |x| >= 0x1p12 or inf or nan */
x = logf(x) + LN2;
} else if i >= 0x3f800000 + (1 << 23) {
/* |x| >= 2 */
x = logf(2.0 * x + 1.0 / (sqrtf(x * x + 1.0) + x));
} else if i >= 0x3f800000 - (12 << 23) {
/* |x| >= 0x1p-12, up to 1.6ulp error in [0.125,0.5] */
x = log1pf(x + x * x / (sqrtf(x * x + 1.0) + 1.0));
} else {
/* |x| < 0x1p-12, raise inexact if x!=0 */
let x1p120 = f32::from_bits(0x7b800000);
force_eval!(x + x1p120);
}
if sign { -x } else { x }
}

182
vendor/libm/src/math/atan.rs vendored Normal file
View File

@@ -0,0 +1,182 @@
/* origin: FreeBSD /usr/src/lib/msun/src/s_atan.c */
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
/* atan(x)
* Method
* 1. Reduce x to positive by atan(x) = -atan(-x).
* 2. According to the integer k=4t+0.25 chopped, t=x, the argument
* is further reduced to one of the following intervals and the
* arctangent of t is evaluated by the corresponding formula:
*
* [0,7/16] atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...)
* [7/16,11/16] atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) )
* [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) )
* [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) )
* [39/16,INF] atan(x) = atan(INF) + atan( -1/t )
*
* Constants:
* The hexadecimal values are the intended ones for the following
* constants. The decimal values may be used, provided that the
* compiler will convert from decimal to binary accurately enough
* to produce the hexadecimal values shown.
*/
use core::f64;
use super::fabs;
const ATANHI: [f64; 4] = [
4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */
7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */
9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */
1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */
];
const ATANLO: [f64; 4] = [
2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */
3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */
1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */
6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */
];
const AT: [f64; 11] = [
3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */
-1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */
1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */
-1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */
9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */
-7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */
6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */
-5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */
4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */
-3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */
1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */
];
/// Arctangent (f64)
///
/// Computes the inverse tangent (arc tangent) of the input value.
/// Returns a value in radians, in the range of -pi/2 to pi/2.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn atan(x: f64) -> f64 {
let mut x = x;
let mut ix = (x.to_bits() >> 32) as u32;
let sign = ix >> 31;
ix &= 0x7fff_ffff;
if ix >= 0x4410_0000 {
if x.is_nan() {
return x;
}
let z = ATANHI[3] + f64::from_bits(0x0380_0000); // 0x1p-120f
return if sign != 0 { -z } else { z };
}
let id = if ix < 0x3fdc_0000 {
/* |x| < 0.4375 */
if ix < 0x3e40_0000 {
/* |x| < 2^-27 */
if ix < 0x0010_0000 {
/* raise underflow for subnormal x */
force_eval!(x as f32);
}
return x;
}
-1
} else {
x = fabs(x);
if ix < 0x3ff30000 {
/* |x| < 1.1875 */
if ix < 0x3fe60000 {
/* 7/16 <= |x| < 11/16 */
x = (2. * x - 1.) / (2. + x);
0
} else {
/* 11/16 <= |x| < 19/16 */
x = (x - 1.) / (x + 1.);
1
}
} else if ix < 0x40038000 {
/* |x| < 2.4375 */
x = (x - 1.5) / (1. + 1.5 * x);
2
} else {
/* 2.4375 <= |x| < 2^66 */
x = -1. / x;
3
}
};
let z = x * x;
let w = z * z;
/* break sum from i=0 to 10 AT[i]z**(i+1) into odd and even poly */
let s1 = z * (AT[0] + w * (AT[2] + w * (AT[4] + w * (AT[6] + w * (AT[8] + w * AT[10])))));
let s2 = w * (AT[1] + w * (AT[3] + w * (AT[5] + w * (AT[7] + w * AT[9]))));
if id < 0 {
return x - x * (s1 + s2);
}
let z = i!(ATANHI, id as usize) - (x * (s1 + s2) - i!(ATANLO, id as usize) - x);
if sign != 0 { -z } else { z }
}
#[cfg(test)]
mod tests {
use core::f64;
use super::atan;
#[test]
fn sanity_check() {
for (input, answer) in [
(3.0_f64.sqrt() / 3.0, f64::consts::FRAC_PI_6),
(1.0, f64::consts::FRAC_PI_4),
(3.0_f64.sqrt(), f64::consts::FRAC_PI_3),
(-3.0_f64.sqrt() / 3.0, -f64::consts::FRAC_PI_6),
(-1.0, -f64::consts::FRAC_PI_4),
(-3.0_f64.sqrt(), -f64::consts::FRAC_PI_3),
]
.iter()
{
assert!(
(atan(*input) - answer) / answer < 1e-5,
"\natan({:.4}/16) = {:.4}, actual: {}",
input * 16.0,
answer,
atan(*input)
);
}
}
#[test]
fn zero() {
assert_eq!(atan(0.0), 0.0);
}
#[test]
fn infinity() {
assert_eq!(atan(f64::INFINITY), f64::consts::FRAC_PI_2);
}
#[test]
fn minus_infinity() {
assert_eq!(atan(f64::NEG_INFINITY), -f64::consts::FRAC_PI_2);
}
#[test]
fn nan() {
assert!(atan(f64::NAN).is_nan());
}
}

131
vendor/libm/src/math/atan2.rs vendored Normal file
View File

@@ -0,0 +1,131 @@
/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2.c */
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunSoft, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*
*/
/* atan2(y,x)
* Method :
* 1. Reduce y to positive by atan2(y,x)=-atan2(-y,x).
* 2. Reduce x to positive by (if x and y are unexceptional):
* ARG (x+iy) = arctan(y/x) ... if x > 0,
* ARG (x+iy) = pi - arctan[y/(-x)] ... if x < 0,
*
* Special cases:
*
* ATAN2((anything), NaN ) is NaN;
* ATAN2(NAN , (anything) ) is NaN;
* ATAN2(+-0, +(anything but NaN)) is +-0 ;
* ATAN2(+-0, -(anything but NaN)) is +-pi ;
* ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2;
* ATAN2(+-(anything but INF and NaN), +INF) is +-0 ;
* ATAN2(+-(anything but INF and NaN), -INF) is +-pi;
* ATAN2(+-INF,+INF ) is +-pi/4 ;
* ATAN2(+-INF,-INF ) is +-3pi/4;
* ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2;
*
* Constants:
* The hexadecimal values are the intended ones for the following
* constants. The decimal values may be used, provided that the
* compiler will convert from decimal to binary accurately enough
* to produce the hexadecimal values shown.
*/
use super::{atan, fabs};
const PI: f64 = 3.1415926535897931160E+00; /* 0x400921FB, 0x54442D18 */
const PI_LO: f64 = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */
/// Arctangent of y/x (f64)
///
/// Computes the inverse tangent (arc tangent) of `y/x`.
/// Produces the correct result even for angles near pi/2 or -pi/2 (that is, when `x` is near 0).
/// Returns a value in radians, in the range of -pi to pi.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn atan2(y: f64, x: f64) -> f64 {
if x.is_nan() || y.is_nan() {
return x + y;
}
let mut ix = (x.to_bits() >> 32) as u32;
let lx = x.to_bits() as u32;
let mut iy = (y.to_bits() >> 32) as u32;
let ly = y.to_bits() as u32;
if ((ix.wrapping_sub(0x3ff00000)) | lx) == 0 {
/* x = 1.0 */
return atan(y);
}
let m = ((iy >> 31) & 1) | ((ix >> 30) & 2); /* 2*sign(x)+sign(y) */
ix &= 0x7fffffff;
iy &= 0x7fffffff;
/* when y = 0 */
if (iy | ly) == 0 {
return match m {
0 | 1 => y, /* atan(+-0,+anything)=+-0 */
2 => PI, /* atan(+0,-anything) = PI */
_ => -PI, /* atan(-0,-anything) =-PI */
};
}
/* when x = 0 */
if (ix | lx) == 0 {
return if m & 1 != 0 { -PI / 2.0 } else { PI / 2.0 };
}
/* when x is INF */
if ix == 0x7ff00000 {
if iy == 0x7ff00000 {
return match m {
0 => PI / 4.0, /* atan(+INF,+INF) */
1 => -PI / 4.0, /* atan(-INF,+INF) */
2 => 3.0 * PI / 4.0, /* atan(+INF,-INF) */
_ => -3.0 * PI / 4.0, /* atan(-INF,-INF) */
};
} else {
return match m {
0 => 0.0, /* atan(+...,+INF) */
1 => -0.0, /* atan(-...,+INF) */
2 => PI, /* atan(+...,-INF) */
_ => -PI, /* atan(-...,-INF) */
};
}
}
/* |y/x| > 0x1p64 */
if ix.wrapping_add(64 << 20) < iy || iy == 0x7ff00000 {
return if m & 1 != 0 { -PI / 2.0 } else { PI / 2.0 };
}
/* z = atan(|y/x|) without spurious underflow */
let z = if (m & 2 != 0) && iy.wrapping_add(64 << 20) < ix {
/* |y/x| < 0x1p-64, x<0 */
0.0
} else {
atan(fabs(y / x))
};
match m {
0 => z, /* atan(+,+) */
1 => -z, /* atan(-,+) */
2 => PI - (z - PI_LO), /* atan(+,-) */
_ => (z - PI_LO) - PI, /* atan(-,-) */
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[cfg_attr(x86_no_sse, ignore = "FIXME(i586): possible incorrect rounding")]
fn sanity_check() {
assert_eq!(atan2(0.0, 1.0), 0.0);
assert_eq!(atan2(0.0, -1.0), PI);
assert_eq!(atan2(-0.0, -1.0), -PI);
assert_eq!(atan2(3.0, 2.0), atan(3.0 / 2.0));
assert_eq!(atan2(2.0, -1.0), atan(2.0 / -1.0) + PI);
assert_eq!(atan2(-2.0, -1.0), atan(-2.0 / -1.0) - PI);
}
}

90
vendor/libm/src/math/atan2f.rs vendored Normal file
View File

@@ -0,0 +1,90 @@
/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2f.c */
/*
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
use super::{atanf, fabsf};
const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */
const PI_LO: f32 = -8.7422776573e-08; /* 0xb3bbbd2e */
/// Arctangent of y/x (f32)
///
/// Computes the inverse tangent (arc tangent) of `y/x`.
/// Produces the correct result even for angles near pi/2 or -pi/2 (that is, when `x` is near 0).
/// Returns a value in radians, in the range of -pi to pi.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn atan2f(y: f32, x: f32) -> f32 {
if x.is_nan() || y.is_nan() {
return x + y;
}
let mut ix = x.to_bits();
let mut iy = y.to_bits();
if ix == 0x3f800000 {
/* x=1.0 */
return atanf(y);
}
let m = ((iy >> 31) & 1) | ((ix >> 30) & 2); /* 2*sign(x)+sign(y) */
ix &= 0x7fffffff;
iy &= 0x7fffffff;
/* when y = 0 */
if iy == 0 {
return match m {
0 | 1 => y, /* atan(+-0,+anything)=+-0 */
2 => PI, /* atan(+0,-anything) = pi */
_ => -PI, /* atan(-0,-anything) =-pi */
};
}
/* when x = 0 */
if ix == 0 {
return if m & 1 != 0 { -PI / 2. } else { PI / 2. };
}
/* when x is INF */
if ix == 0x7f800000 {
return if iy == 0x7f800000 {
match m {
0 => PI / 4., /* atan(+INF,+INF) */
1 => -PI / 4., /* atan(-INF,+INF) */
2 => 3. * PI / 4., /* atan(+INF,-INF)*/
_ => -3. * PI / 4., /* atan(-INF,-INF)*/
}
} else {
match m {
0 => 0., /* atan(+...,+INF) */
1 => -0., /* atan(-...,+INF) */
2 => PI, /* atan(+...,-INF) */
_ => -PI, /* atan(-...,-INF) */
}
};
}
/* |y/x| > 0x1p26 */
if (ix + (26 << 23) < iy) || (iy == 0x7f800000) {
return if m & 1 != 0 { -PI / 2. } else { PI / 2. };
}
/* z = atan(|y/x|) with correct underflow */
let z = if (m & 2 != 0) && (iy + (26 << 23) < ix) {
/*|y/x| < 0x1p-26, x < 0 */
0.
} else {
atanf(fabsf(y / x))
};
match m {
0 => z, /* atan(+,+) */
1 => -z, /* atan(-,+) */
2 => PI - (z - PI_LO), /* atan(+,-) */
_ => (z - PI_LO) - PI, /* case 3 */ /* atan(-,-) */
}
}

108
vendor/libm/src/math/atanf.rs vendored Normal file
View File

@@ -0,0 +1,108 @@
/* origin: FreeBSD /usr/src/lib/msun/src/s_atanf.c */
/*
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
use super::fabsf;
const ATAN_HI: [f32; 4] = [
4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */
7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */
9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */
1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */
];
const ATAN_LO: [f32; 4] = [
5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */
3.7748947079e-08, /* atan(1.0)lo 0x33222168 */
3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */
7.5497894159e-08, /* atan(inf)lo 0x33a22168 */
];
const A_T: [f32; 5] = [
3.3333328366e-01,
-1.9999158382e-01,
1.4253635705e-01,
-1.0648017377e-01,
6.1687607318e-02,
];
/// Arctangent (f32)
///
/// Computes the inverse tangent (arc tangent) of the input value.
/// Returns a value in radians, in the range of -pi/2 to pi/2.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn atanf(mut x: f32) -> f32 {
let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120)
let z: f32;
let mut ix = x.to_bits();
let sign = (ix >> 31) != 0;
ix &= 0x7fffffff;
if ix >= 0x4c800000 {
/* if |x| >= 2**26 */
if x.is_nan() {
return x;
}
z = i!(ATAN_HI, 3) + x1p_120;
return if sign { -z } else { z };
}
let id = if ix < 0x3ee00000 {
/* |x| < 0.4375 */
if ix < 0x39800000 {
/* |x| < 2**-12 */
if ix < 0x00800000 {
/* raise underflow for subnormal x */
force_eval!(x * x);
}
return x;
}
-1
} else {
x = fabsf(x);
if ix < 0x3f980000 {
/* |x| < 1.1875 */
if ix < 0x3f300000 {
/* 7/16 <= |x| < 11/16 */
x = (2. * x - 1.) / (2. + x);
0
} else {
/* 11/16 <= |x| < 19/16 */
x = (x - 1.) / (x + 1.);
1
}
} else if ix < 0x401c0000 {
/* |x| < 2.4375 */
x = (x - 1.5) / (1. + 1.5 * x);
2
} else {
/* 2.4375 <= |x| < 2**26 */
x = -1. / x;
3
}
};
/* end of argument reduction */
z = x * x;
let w = z * z;
/* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
let s1 = z * (i!(A_T, 0) + w * (i!(A_T, 2) + w * i!(A_T, 4)));
let s2 = w * (i!(A_T, 1) + w * i!(A_T, 3));
if id < 0 {
return x - x * (s1 + s2);
}
let id = id as usize;
let z = i!(ATAN_HI, id) - ((x * (s1 + s2) - i!(ATAN_LO, id)) - x);
if sign { -z } else { z }
}

33
vendor/libm/src/math/atanh.rs vendored Normal file
View File

@@ -0,0 +1,33 @@
use super::log1p;
/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */
/// Inverse hyperbolic tangent (f64)
///
/// Calculates the inverse hyperbolic tangent of `x`.
/// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn atanh(x: f64) -> f64 {
let u = x.to_bits();
let e = ((u >> 52) as usize) & 0x7ff;
let sign = (u >> 63) != 0;
/* |x| */
let mut y = f64::from_bits(u & 0x7fff_ffff_ffff_ffff);
if e < 0x3ff - 1 {
if e < 0x3ff - 32 {
/* handle underflow */
if e == 0 {
force_eval!(y as f32);
}
} else {
/* |x| < 0.5, up to 1.7ulp error */
y = 0.5 * log1p(2.0 * y + 2.0 * y * y / (1.0 - y));
}
} else {
/* avoid overflow */
y = 0.5 * log1p(2.0 * (y / (1.0 - y)));
}
if sign { -y } else { y }
}

33
vendor/libm/src/math/atanhf.rs vendored Normal file
View File

@@ -0,0 +1,33 @@
use super::log1pf;
/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */
/// Inverse hyperbolic tangent (f32)
///
/// Calculates the inverse hyperbolic tangent of `x`.
/// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn atanhf(mut x: f32) -> f32 {
let mut u = x.to_bits();
let sign = (u >> 31) != 0;
/* |x| */
u &= 0x7fffffff;
x = f32::from_bits(u);
if u < 0x3f800000 - (1 << 23) {
if u < 0x3f800000 - (32 << 23) {
/* handle underflow */
if u < (1 << 23) {
force_eval!(x * x);
}
} else {
/* |x| < 0.5, up to 1.7ulp error */
x = 0.5 * log1pf(2.0 * x + 2.0 * x * x / (1.0 - x));
}
} else {
/* avoid overflow */
x = 0.5 * log1pf(2.0 * (x / (1.0 - x)));
}
if sign { -x } else { x }
}

219
vendor/libm/src/math/cbrt.rs vendored Normal file
View File

@@ -0,0 +1,219 @@
/* SPDX-License-Identifier: MIT */
/* origin: core-math/src/binary64/cbrt/cbrt.c
* Copyright (c) 2021-2022 Alexei Sibidanov.
* Ported to Rust in 2025 by Trevor Gross.
*/
use super::Float;
use super::support::{FpResult, Round, cold_path};
/// Compute the cube root of the argument.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn cbrt(x: f64) -> f64 {
cbrt_round(x, Round::Nearest).val
}
pub fn cbrt_round(x: f64, round: Round) -> FpResult<f64> {
const ESCALE: [f64; 3] = [
1.0,
hf64!("0x1.428a2f98d728bp+0"), /* 2^(1/3) */
hf64!("0x1.965fea53d6e3dp+0"), /* 2^(2/3) */
];
/* the polynomial c0+c1*x+c2*x^2+c3*x^3 approximates x^(1/3) on [1,2]
with maximal error < 9.2e-5 (attained at x=2) */
const C: [f64; 4] = [
hf64!("0x1.1b0babccfef9cp-1"),
hf64!("0x1.2c9a3e94d1da5p-1"),
hf64!("-0x1.4dc30b1a1ddbap-3"),
hf64!("0x1.7a8d3e4ec9b07p-6"),
];
let u0: f64 = hf64!("0x1.5555555555555p-2");
let u1: f64 = hf64!("0x1.c71c71c71c71cp-3");
let rsc = [1.0, -1.0, 0.5, -0.5, 0.25, -0.25];
let off = [hf64!("0x1p-53"), 0.0, 0.0, 0.0];
/* rm=0 for rounding to nearest, and other values for directed roundings */
let hx: u64 = x.to_bits();
let mut mant: u64 = hx & f64::SIG_MASK;
let sign: u64 = hx >> 63;
let mut e: u32 = (hx >> f64::SIG_BITS) as u32 & f64::EXP_SAT;
if ((e + 1) & f64::EXP_SAT) < 2 {
cold_path();
let ix: u64 = hx & !f64::SIGN_MASK;
/* 0, inf, nan: we return x + x instead of simply x,
to that for x a signaling NaN, it correctly triggers
the invalid exception. */
if e == f64::EXP_SAT || ix == 0 {
return FpResult::ok(x + x);
}
let nz = ix.leading_zeros() - 11; /* subnormal */
mant <<= nz;
mant &= f64::SIG_MASK;
e = e.wrapping_sub(nz - 1);
}
e = e.wrapping_add(3072);
let cvt1: u64 = mant | (0x3ffu64 << 52);
let mut cvt5: u64 = cvt1;
let et: u32 = e / 3;
let it: u32 = e % 3;
/* 2^(3k+it) <= x < 2^(3k+it+1), with 0 <= it <= 3 */
cvt5 += u64::from(it) << f64::SIG_BITS;
cvt5 |= sign << 63;
let zz: f64 = f64::from_bits(cvt5);
/* cbrt(x) = cbrt(zz)*2^(et-1365) where 1 <= zz < 8 */
let mut isc: u64 = ESCALE[it as usize].to_bits(); // todo: index
isc |= sign << 63;
let cvt2: u64 = isc;
let z: f64 = f64::from_bits(cvt1);
/* cbrt(zz) = cbrt(z)*isc, where isc encodes 1, 2^(1/3) or 2^(2/3),
and 1 <= z < 2 */
let r: f64 = 1.0 / z;
let rr: f64 = r * rsc[((it as usize) << 1) | sign as usize];
let z2: f64 = z * z;
let c0: f64 = C[0] + z * C[1];
let c2: f64 = C[2] + z * C[3];
let mut y: f64 = c0 + z2 * c2;
let mut y2: f64 = y * y;
/* y is an approximation of z^(1/3) */
let mut h: f64 = y2 * (y * r) - 1.0;
/* h determines the error between y and z^(1/3) */
y -= (h * y) * (u0 - u1 * h);
/* The correction y -= (h*y)*(u0 - u1*h) corresponds to a cubic variant
of Newton's method, with the function f(y) = 1-z/y^3. */
y *= f64::from_bits(cvt2);
/* Now y is an approximation of zz^(1/3),
* and rr an approximation of 1/zz. We now perform another iteration of
* Newton-Raphson, this time with a linear approximation only. */
y2 = y * y;
let mut y2l: f64 = y.fma(y, -y2);
/* y2 + y2l = y^2 exactly */
let mut y3: f64 = y2 * y;
let mut y3l: f64 = y.fma(y2, -y3) + y * y2l;
/* y3 + y3l approximates y^3 with about 106 bits of accuracy */
h = ((y3 - zz) + y3l) * rr;
let mut dy: f64 = h * (y * u0);
/* the approximation of zz^(1/3) is y - dy */
let mut y1: f64 = y - dy;
dy = (y - y1) - dy;
/* the approximation of zz^(1/3) is now y1 + dy, where |dy| < 1/2 ulp(y)
* (for rounding to nearest) */
let mut ady: f64 = dy.abs();
/* For directed roundings, ady0 is tiny when dy is tiny, or ady0 is near
* from ulp(1);
* for rounding to nearest, ady0 is tiny when dy is near from 1/2 ulp(1),
* or from 3/2 ulp(1). */
let mut ady0: f64 = (ady - off[round as usize]).abs();
let mut ady1: f64 = (ady - (hf64!("0x1p-52") + off[round as usize])).abs();
if ady0 < hf64!("0x1p-75") || ady1 < hf64!("0x1p-75") {
cold_path();
y2 = y1 * y1;
y2l = y1.fma(y1, -y2);
y3 = y2 * y1;
y3l = y1.fma(y2, -y3) + y1 * y2l;
h = ((y3 - zz) + y3l) * rr;
dy = h * (y1 * u0);
y = y1 - dy;
dy = (y1 - y) - dy;
y1 = y;
ady = dy.abs();
ady0 = (ady - off[round as usize]).abs();
ady1 = (ady - (hf64!("0x1p-52") + off[round as usize])).abs();
if ady0 < hf64!("0x1p-98") || ady1 < hf64!("0x1p-98") {
cold_path();
let azz: f64 = zz.abs();
// ~ 0x1.79d15d0e8d59b80000000000000ffc3dp+0
if azz == hf64!("0x1.9b78223aa307cp+1") {
y1 = hf64!("0x1.79d15d0e8d59cp+0").copysign(zz);
}
// ~ 0x1.de87aa837820e80000000000001c0f08p+0
if azz == hf64!("0x1.a202bfc89ddffp+2") {
y1 = hf64!("0x1.de87aa837820fp+0").copysign(zz);
}
if round != Round::Nearest {
let wlist = [
(hf64!("0x1.3a9ccd7f022dbp+0"), hf64!("0x1.1236160ba9b93p+0")), // ~ 0x1.1236160ba9b930000000000001e7e8fap+0
(hf64!("0x1.7845d2faac6fep+0"), hf64!("0x1.23115e657e49cp+0")), // ~ 0x1.23115e657e49c0000000000001d7a799p+0
(hf64!("0x1.d1ef81cbbbe71p+0"), hf64!("0x1.388fb44cdcf5ap+0")), // ~ 0x1.388fb44cdcf5a0000000000002202c55p+0
(hf64!("0x1.0a2014f62987cp+1"), hf64!("0x1.46bcbf47dc1e8p+0")), // ~ 0x1.46bcbf47dc1e8000000000000303aa2dp+0
(hf64!("0x1.fe18a044a5501p+1"), hf64!("0x1.95decfec9c904p+0")), // ~ 0x1.95decfec9c9040000000000000159e8ep+0
(hf64!("0x1.a6bb8c803147bp+2"), hf64!("0x1.e05335a6401dep+0")), // ~ 0x1.e05335a6401de00000000000027ca017p+0
(hf64!("0x1.ac8538a031cbdp+2"), hf64!("0x1.e281d87098de8p+0")), // ~ 0x1.e281d87098de80000000000000ee9314p+0
];
for (a, b) in wlist {
if azz == a {
let tmp = if round as u64 + sign == 2 {
hf64!("0x1p-52")
} else {
0.0
};
y1 = (b + tmp).copysign(zz);
}
}
}
}
}
let mut cvt3: u64 = y1.to_bits();
cvt3 = cvt3.wrapping_add(((et.wrapping_sub(342).wrapping_sub(1023)) as u64) << 52);
let m0: u64 = cvt3 << 30;
let m1 = m0 >> 63;
if (m0 ^ m1) <= (1u64 << 30) {
cold_path();
let mut cvt4: u64 = y1.to_bits();
cvt4 = (cvt4 + (164 << 15)) & 0xffffffffffff0000u64;
if ((f64::from_bits(cvt4) - y1) - dy).abs() < hf64!("0x1p-60") || (zz).abs() == 1.0 {
cvt3 = (cvt3 + (1u64 << 15)) & 0xffffffffffff0000u64;
}
}
FpResult::ok(f64::from_bits(cvt3))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn spot_checks() {
if !cfg!(x86_no_sse) {
// Exposes a rounding mode problem. Ignored on i586 because of inaccurate FMA.
assert_biteq!(
cbrt(f64::from_bits(0xf7f792b28f600000)),
f64::from_bits(0xd29ce68655d962f3)
);
}
}
}

75
vendor/libm/src/math/cbrtf.rs vendored Normal file
View File

@@ -0,0 +1,75 @@
/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrtf.c */
/*
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
* Debugged and optimized by Bruce D. Evans.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
/* cbrtf(x)
* Return cube root of x
*/
use core::f32;
const B1: u32 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */
const B2: u32 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */
/// Cube root (f32)
///
/// Computes the cube root of the argument.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn cbrtf(x: f32) -> f32 {
let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24
let mut r: f64;
let mut t: f64;
let mut ui: u32 = x.to_bits();
let mut hx: u32 = ui & 0x7fffffff;
if hx >= 0x7f800000 {
/* cbrt(NaN,INF) is itself */
return x + x;
}
/* rough cbrt to 5 bits */
if hx < 0x00800000 {
/* zero or subnormal? */
if hx == 0 {
return x; /* cbrt(+-0) is itself */
}
ui = (x * x1p24).to_bits();
hx = ui & 0x7fffffff;
hx = hx / 3 + B2;
} else {
hx = hx / 3 + B1;
}
ui &= 0x80000000;
ui |= hx;
/*
* First step Newton iteration (solving t*t-x/t == 0) to 16 bits. In
* double precision so that its terms can be arranged for efficiency
* without causing overflow or underflow.
*/
t = f32::from_bits(ui) as f64;
r = t * t * t;
t = t * (x as f64 + x as f64 + r) / (x as f64 + r + r);
/*
* Second step Newton iteration to 47 bits. In double precision for
* efficiency and accuracy.
*/
r = t * t * t;
t = t * (x as f64 + x as f64 + r) / (x as f64 + r + r);
/* rounding to 24 bits is perfect in round-to-nearest mode */
t as f32
}

46
vendor/libm/src/math/ceil.rs vendored Normal file
View File

@@ -0,0 +1,46 @@
/// Ceil (f16)
///
/// Finds the nearest integer greater than or equal to `x`.
#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn ceilf16(x: f16) -> f16 {
super::generic::ceil(x)
}
/// Ceil (f32)
///
/// Finds the nearest integer greater than or equal to `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn ceilf(x: f32) -> f32 {
select_implementation! {
name: ceilf,
use_arch: all(target_arch = "wasm32", intrinsics_enabled),
args: x,
}
super::generic::ceil(x)
}
/// Ceil (f64)
///
/// Finds the nearest integer greater than or equal to `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn ceil(x: f64) -> f64 {
select_implementation! {
name: ceil,
use_arch: all(target_arch = "wasm32", intrinsics_enabled),
use_arch_required: all(target_arch = "x86", not(target_feature = "sse2")),
args: x,
}
super::generic::ceil(x)
}
/// Ceil (f128)
///
/// Finds the nearest integer greater than or equal to `x`.
#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn ceilf128(x: f128) -> f128 {
super::generic::ceil(x)
}

88
vendor/libm/src/math/copysign.rs vendored Normal file
View File

@@ -0,0 +1,88 @@
/// Sign of Y, magnitude of X (f16)
///
/// Constructs a number with the magnitude (absolute value) of its
/// first argument, `x`, and the sign of its second argument, `y`.
#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn copysignf16(x: f16, y: f16) -> f16 {
super::generic::copysign(x, y)
}
/// Sign of Y, magnitude of X (f32)
///
/// Constructs a number with the magnitude (absolute value) of its
/// first argument, `x`, and the sign of its second argument, `y`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn copysignf(x: f32, y: f32) -> f32 {
super::generic::copysign(x, y)
}
/// Sign of Y, magnitude of X (f64)
///
/// Constructs a number with the magnitude (absolute value) of its
/// first argument, `x`, and the sign of its second argument, `y`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn copysign(x: f64, y: f64) -> f64 {
super::generic::copysign(x, y)
}
/// Sign of Y, magnitude of X (f128)
///
/// Constructs a number with the magnitude (absolute value) of its
/// first argument, `x`, and the sign of its second argument, `y`.
#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn copysignf128(x: f128, y: f128) -> f128 {
super::generic::copysign(x, y)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::support::Float;
fn spec_test<F: Float>(f: impl Fn(F, F) -> F) {
assert_biteq!(f(F::ZERO, F::ZERO), F::ZERO);
assert_biteq!(f(F::NEG_ZERO, F::ZERO), F::ZERO);
assert_biteq!(f(F::ZERO, F::NEG_ZERO), F::NEG_ZERO);
assert_biteq!(f(F::NEG_ZERO, F::NEG_ZERO), F::NEG_ZERO);
assert_biteq!(f(F::ONE, F::ONE), F::ONE);
assert_biteq!(f(F::NEG_ONE, F::ONE), F::ONE);
assert_biteq!(f(F::ONE, F::NEG_ONE), F::NEG_ONE);
assert_biteq!(f(F::NEG_ONE, F::NEG_ONE), F::NEG_ONE);
assert_biteq!(f(F::INFINITY, F::INFINITY), F::INFINITY);
assert_biteq!(f(F::NEG_INFINITY, F::INFINITY), F::INFINITY);
assert_biteq!(f(F::INFINITY, F::NEG_INFINITY), F::NEG_INFINITY);
assert_biteq!(f(F::NEG_INFINITY, F::NEG_INFINITY), F::NEG_INFINITY);
// Not required but we expect it
assert_biteq!(f(F::NAN, F::NAN), F::NAN);
assert_biteq!(f(F::NEG_NAN, F::NAN), F::NAN);
assert_biteq!(f(F::NAN, F::NEG_NAN), F::NEG_NAN);
assert_biteq!(f(F::NEG_NAN, F::NEG_NAN), F::NEG_NAN);
}
#[test]
#[cfg(f16_enabled)]
fn spec_tests_f16() {
spec_test::<f16>(copysignf16);
}
#[test]
fn spec_tests_f32() {
spec_test::<f32>(copysignf);
}
#[test]
fn spec_tests_f64() {
spec_test::<f64>(copysign);
}
#[test]
#[cfg(f128_enabled)]
fn spec_tests_f128() {
spec_test::<f128>(copysignf128);
}
}

8
vendor/libm/src/math/copysignf.rs vendored Normal file
View File

@@ -0,0 +1,8 @@
/// Sign of Y, magnitude of X (f32)
///
/// Constructs a number with the magnitude (absolute value) of its
/// first argument, `x`, and the sign of its second argument, `y`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn copysignf(x: f32, y: f32) -> f32 {
super::generic::copysign(x, y)
}

8
vendor/libm/src/math/copysignf128.rs vendored Normal file
View File

@@ -0,0 +1,8 @@
/// Sign of Y, magnitude of X (f128)
///
/// Constructs a number with the magnitude (absolute value) of its
/// first argument, `x`, and the sign of its second argument, `y`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn copysignf128(x: f128, y: f128) -> f128 {
super::generic::copysign(x, y)
}

8
vendor/libm/src/math/copysignf16.rs vendored Normal file
View File

@@ -0,0 +1,8 @@
/// Sign of Y, magnitude of X (f16)
///
/// Constructs a number with the magnitude (absolute value) of its
/// first argument, `x`, and the sign of its second argument, `y`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn copysignf16(x: f16, y: f16) -> f16 {
super::generic::copysign(x, y)
}

77
vendor/libm/src/math/cos.rs vendored Normal file
View File

@@ -0,0 +1,77 @@
// origin: FreeBSD /usr/src/lib/msun/src/s_cos.c */
//
// ====================================================
// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
//
// Developed at SunPro, a Sun Microsystems, Inc. business.
// Permission to use, copy, modify, and distribute this
// software is freely granted, provided that this notice
// is preserved.
// ====================================================
use super::{k_cos, k_sin, rem_pio2};
// cos(x)
// Return cosine function of x.
//
// kernel function:
// k_sin ... sine function on [-pi/4,pi/4]
// k_cos ... cosine function on [-pi/4,pi/4]
// rem_pio2 ... argument reduction routine
//
// Method.
// Let S,C and T denote the sin, cos and tan respectively on
// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
// in [-pi/4 , +pi/4], and let n = k mod 4.
// We have
//
// n sin(x) cos(x) tan(x)
// ----------------------------------------------------------
// 0 S C T
// 1 C -S -1/T
// 2 -S -C T
// 3 -C S -1/T
// ----------------------------------------------------------
//
// Special cases:
// Let trig be any of sin, cos, or tan.
// trig(+-INF) is NaN, with signals;
// trig(NaN) is that NaN;
//
// Accuracy:
// TRIG(x) returns trig(x) nearly rounded
//
/// The cosine of `x` (f64).
///
/// `x` is specified in radians.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn cos(x: f64) -> f64 {
let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff;
/* |x| ~< pi/4 */
if ix <= 0x3fe921fb {
if ix < 0x3e46a09e {
/* if x < 2**-27 * sqrt(2) */
/* raise inexact if x != 0 */
if x as i32 == 0 {
return 1.0;
}
}
return k_cos(x, 0.0);
}
/* cos(Inf or NaN) is NaN */
if ix >= 0x7ff00000 {
return x - x;
}
/* argument reduction needed */
let (n, y0, y1) = rem_pio2(x);
match n & 3 {
0 => k_cos(y0, y1),
1 => -k_sin(y0, y1, 1),
2 => -k_cos(y0, y1),
_ => k_sin(y0, y1, 1),
}
}

86
vendor/libm/src/math/cosf.rs vendored Normal file
View File

@@ -0,0 +1,86 @@
/* origin: FreeBSD /usr/src/lib/msun/src/s_cosf.c */
/*
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
* Optimized by Bruce D. Evans.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
use core::f64::consts::FRAC_PI_2;
use super::{k_cosf, k_sinf, rem_pio2f};
/* Small multiples of pi/2 rounded to double precision. */
const C1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */
const C2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */
const C3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */
const C4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */
/// The cosine of `x` (f32).
///
/// `x` is specified in radians.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn cosf(x: f32) -> f32 {
let x64 = x as f64;
let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120
let mut ix = x.to_bits();
let sign = (ix >> 31) != 0;
ix &= 0x7fffffff;
if ix <= 0x3f490fda {
/* |x| ~<= pi/4 */
if ix < 0x39800000 {
/* |x| < 2**-12 */
/* raise inexact if x != 0 */
force_eval!(x + x1p120);
return 1.;
}
return k_cosf(x64);
}
if ix <= 0x407b53d1 {
/* |x| ~<= 5*pi/4 */
if ix > 0x4016cbe3 {
/* |x| ~> 3*pi/4 */
return -k_cosf(if sign { x64 + C2_PIO2 } else { x64 - C2_PIO2 });
} else if sign {
return k_sinf(x64 + C1_PIO2);
} else {
return k_sinf(C1_PIO2 - x64);
}
}
if ix <= 0x40e231d5 {
/* |x| ~<= 9*pi/4 */
if ix > 0x40afeddf {
/* |x| ~> 7*pi/4 */
return k_cosf(if sign { x64 + C4_PIO2 } else { x64 - C4_PIO2 });
} else if sign {
return k_sinf(-x64 - C3_PIO2);
} else {
return k_sinf(x64 - C3_PIO2);
}
}
/* cos(Inf or NaN) is NaN */
if ix >= 0x7f800000 {
return x - x;
}
/* general argument reduction needed */
let (n, y) = rem_pio2f(x);
match n & 3 {
0 => k_cosf(y),
1 => k_sinf(-y),
2 => -k_cosf(y),
_ => k_sinf(y),
}
}

36
vendor/libm/src/math/cosh.rs vendored Normal file
View File

@@ -0,0 +1,36 @@
use super::{exp, expm1, k_expo2};
/// Hyperbolic cosine (f64)
///
/// Computes the hyperbolic cosine of the argument x.
/// Is defined as `(exp(x) + exp(-x))/2`
/// Angles are specified in radians.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn cosh(mut x: f64) -> f64 {
/* |x| */
let mut ix = x.to_bits();
ix &= 0x7fffffffffffffff;
x = f64::from_bits(ix);
let w = ix >> 32;
/* |x| < log(2) */
if w < 0x3fe62e42 {
if w < 0x3ff00000 - (26 << 20) {
let x1p120 = f64::from_bits(0x4770000000000000);
force_eval!(x + x1p120);
return 1.;
}
let t = expm1(x); // exponential minus 1
return 1. + t * t / (2. * (1. + t));
}
/* |x| < log(DBL_MAX) */
if w < 0x40862e42 {
let t = exp(x);
/* note: if x>log(0x1p26) then the 1/t is not needed */
return 0.5 * (t + 1. / t);
}
/* |x| > log(DBL_MAX) or nan */
k_expo2(x)
}

36
vendor/libm/src/math/coshf.rs vendored Normal file
View File

@@ -0,0 +1,36 @@
use super::{expf, expm1f, k_expo2f};
/// Hyperbolic cosine (f64)
///
/// Computes the hyperbolic cosine of the argument x.
/// Is defined as `(exp(x) + exp(-x))/2`
/// Angles are specified in radians.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn coshf(mut x: f32) -> f32 {
let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120
/* |x| */
let mut ix = x.to_bits();
ix &= 0x7fffffff;
x = f32::from_bits(ix);
let w = ix;
/* |x| < log(2) */
if w < 0x3f317217 {
if w < (0x3f800000 - (12 << 23)) {
force_eval!(x + x1p120);
return 1.;
}
let t = expm1f(x);
return 1. + t * t / (2. * (1. + t));
}
/* |x| < log(FLT_MAX) */
if w < 0x42b17217 {
let t = expf(x);
return 0.5 * (t + 1. / t);
}
/* |x| > log(FLT_MAX) or nan */
k_expo2f(x)
}

314
vendor/libm/src/math/erf.rs vendored Normal file
View File

@@ -0,0 +1,314 @@
use super::{exp, fabs, get_high_word, with_set_low_word};
/* origin: FreeBSD /usr/src/lib/msun/src/s_erf.c */
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
/* double erf(double x)
* double erfc(double x)
* x
* 2 |\
* erf(x) = --------- | exp(-t*t)dt
* sqrt(pi) \|
* 0
*
* erfc(x) = 1-erf(x)
* Note that
* erf(-x) = -erf(x)
* erfc(-x) = 2 - erfc(x)
*
* Method:
* 1. For |x| in [0, 0.84375]
* erf(x) = x + x*R(x^2)
* erfc(x) = 1 - erf(x) if x in [-.84375,0.25]
* = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375]
* where R = P/Q where P is an odd poly of degree 8 and
* Q is an odd poly of degree 10.
* -57.90
* | R - (erf(x)-x)/x | <= 2
*
*
* Remark. The formula is derived by noting
* erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....)
* and that
* 2/sqrt(pi) = 1.128379167095512573896158903121545171688
* is close to one. The interval is chosen because the fix
* point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is
* near 0.6174), and by some experiment, 0.84375 is chosen to
* guarantee the error is less than one ulp for erf.
*
* 2. For |x| in [0.84375,1.25], let s = |x| - 1, and
* c = 0.84506291151 rounded to single (24 bits)
* erf(x) = sign(x) * (c + P1(s)/Q1(s))
* erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0
* 1+(c+P1(s)/Q1(s)) if x < 0
* |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06
* Remark: here we use the taylor series expansion at x=1.
* erf(1+s) = erf(1) + s*Poly(s)
* = 0.845.. + P1(s)/Q1(s)
* That is, we use rational approximation to approximate
* erf(1+s) - (c = (single)0.84506291151)
* Note that |P1/Q1|< 0.078 for x in [0.84375,1.25]
* where
* P1(s) = degree 6 poly in s
* Q1(s) = degree 6 poly in s
*
* 3. For x in [1.25,1/0.35(~2.857143)],
* erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1)
* erf(x) = 1 - erfc(x)
* where
* R1(z) = degree 7 poly in z, (z=1/x^2)
* S1(z) = degree 8 poly in z
*
* 4. For x in [1/0.35,28]
* erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0
* = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6<x<0
* = 2.0 - tiny (if x <= -6)
* erf(x) = sign(x)*(1.0 - erfc(x)) if x < 6, else
* erf(x) = sign(x)*(1.0 - tiny)
* where
* R2(z) = degree 6 poly in z, (z=1/x^2)
* S2(z) = degree 7 poly in z
*
* Note1:
* To compute exp(-x*x-0.5625+R/S), let s be a single
* precision number and s := x; then
* -x*x = -s*s + (s-x)*(s+x)
* exp(-x*x-0.5626+R/S) =
* exp(-s*s-0.5625)*exp((s-x)*(s+x)+R/S);
* Note2:
* Here 4 and 5 make use of the asymptotic series
* exp(-x*x)
* erfc(x) ~ ---------- * ( 1 + Poly(1/x^2) )
* x*sqrt(pi)
* We use rational approximation to approximate
* g(s)=f(1/x^2) = log(erfc(x)*x) - x*x + 0.5625
* Here is the error bound for R1/S1 and R2/S2
* |R1/S1 - f(x)| < 2**(-62.57)
* |R2/S2 - f(x)| < 2**(-61.52)
*
* 5. For inf > x >= 28
* erf(x) = sign(x) *(1 - tiny) (raise inexact)
* erfc(x) = tiny*tiny (raise underflow) if x > 0
* = 2 - tiny if x<0
*
* 7. Special case:
* erf(0) = 0, erf(inf) = 1, erf(-inf) = -1,
* erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2,
* erfc/erf(NaN) is NaN
*/
const ERX: f64 = 8.45062911510467529297e-01; /* 0x3FEB0AC1, 0x60000000 */
/*
* Coefficients for approximation to erf on [0,0.84375]
*/
const EFX8: f64 = 1.02703333676410069053e+00; /* 0x3FF06EBA, 0x8214DB69 */
const PP0: f64 = 1.28379167095512558561e-01; /* 0x3FC06EBA, 0x8214DB68 */
const PP1: f64 = -3.25042107247001499370e-01; /* 0xBFD4CD7D, 0x691CB913 */
const PP2: f64 = -2.84817495755985104766e-02; /* 0xBF9D2A51, 0xDBD7194F */
const PP3: f64 = -5.77027029648944159157e-03; /* 0xBF77A291, 0x236668E4 */
const PP4: f64 = -2.37630166566501626084e-05; /* 0xBEF8EAD6, 0x120016AC */
const QQ1: f64 = 3.97917223959155352819e-01; /* 0x3FD97779, 0xCDDADC09 */
const QQ2: f64 = 6.50222499887672944485e-02; /* 0x3FB0A54C, 0x5536CEBA */
const QQ3: f64 = 5.08130628187576562776e-03; /* 0x3F74D022, 0xC4D36B0F */
const QQ4: f64 = 1.32494738004321644526e-04; /* 0x3F215DC9, 0x221C1A10 */
const QQ5: f64 = -3.96022827877536812320e-06; /* 0xBED09C43, 0x42A26120 */
/*
* Coefficients for approximation to erf in [0.84375,1.25]
*/
const PA0: f64 = -2.36211856075265944077e-03; /* 0xBF6359B8, 0xBEF77538 */
const PA1: f64 = 4.14856118683748331666e-01; /* 0x3FDA8D00, 0xAD92B34D */
const PA2: f64 = -3.72207876035701323847e-01; /* 0xBFD7D240, 0xFBB8C3F1 */
const PA3: f64 = 3.18346619901161753674e-01; /* 0x3FD45FCA, 0x805120E4 */
const PA4: f64 = -1.10894694282396677476e-01; /* 0xBFBC6398, 0x3D3E28EC */
const PA5: f64 = 3.54783043256182359371e-02; /* 0x3FA22A36, 0x599795EB */
const PA6: f64 = -2.16637559486879084300e-03; /* 0xBF61BF38, 0x0A96073F */
const QA1: f64 = 1.06420880400844228286e-01; /* 0x3FBB3E66, 0x18EEE323 */
const QA2: f64 = 5.40397917702171048937e-01; /* 0x3FE14AF0, 0x92EB6F33 */
const QA3: f64 = 7.18286544141962662868e-02; /* 0x3FB2635C, 0xD99FE9A7 */
const QA4: f64 = 1.26171219808761642112e-01; /* 0x3FC02660, 0xE763351F */
const QA5: f64 = 1.36370839120290507362e-02; /* 0x3F8BEDC2, 0x6B51DD1C */
const QA6: f64 = 1.19844998467991074170e-02; /* 0x3F888B54, 0x5735151D */
/*
* Coefficients for approximation to erfc in [1.25,1/0.35]
*/
const RA0: f64 = -9.86494403484714822705e-03; /* 0xBF843412, 0x600D6435 */
const RA1: f64 = -6.93858572707181764372e-01; /* 0xBFE63416, 0xE4BA7360 */
const RA2: f64 = -1.05586262253232909814e+01; /* 0xC0251E04, 0x41B0E726 */
const RA3: f64 = -6.23753324503260060396e+01; /* 0xC04F300A, 0xE4CBA38D */
const RA4: f64 = -1.62396669462573470355e+02; /* 0xC0644CB1, 0x84282266 */
const RA5: f64 = -1.84605092906711035994e+02; /* 0xC067135C, 0xEBCCABB2 */
const RA6: f64 = -8.12874355063065934246e+01; /* 0xC0545265, 0x57E4D2F2 */
const RA7: f64 = -9.81432934416914548592e+00; /* 0xC023A0EF, 0xC69AC25C */
const SA1: f64 = 1.96512716674392571292e+01; /* 0x4033A6B9, 0xBD707687 */
const SA2: f64 = 1.37657754143519042600e+02; /* 0x4061350C, 0x526AE721 */
const SA3: f64 = 4.34565877475229228821e+02; /* 0x407B290D, 0xD58A1A71 */
const SA4: f64 = 6.45387271733267880336e+02; /* 0x40842B19, 0x21EC2868 */
const SA5: f64 = 4.29008140027567833386e+02; /* 0x407AD021, 0x57700314 */
const SA6: f64 = 1.08635005541779435134e+02; /* 0x405B28A3, 0xEE48AE2C */
const SA7: f64 = 6.57024977031928170135e+00; /* 0x401A47EF, 0x8E484A93 */
const SA8: f64 = -6.04244152148580987438e-02; /* 0xBFAEEFF2, 0xEE749A62 */
/*
* Coefficients for approximation to erfc in [1/.35,28]
*/
const RB0: f64 = -9.86494292470009928597e-03; /* 0xBF843412, 0x39E86F4A */
const RB1: f64 = -7.99283237680523006574e-01; /* 0xBFE993BA, 0x70C285DE */
const RB2: f64 = -1.77579549177547519889e+01; /* 0xC031C209, 0x555F995A */
const RB3: f64 = -1.60636384855821916062e+02; /* 0xC064145D, 0x43C5ED98 */
const RB4: f64 = -6.37566443368389627722e+02; /* 0xC083EC88, 0x1375F228 */
const RB5: f64 = -1.02509513161107724954e+03; /* 0xC0900461, 0x6A2E5992 */
const RB6: f64 = -4.83519191608651397019e+02; /* 0xC07E384E, 0x9BDC383F */
const SB1: f64 = 3.03380607434824582924e+01; /* 0x403E568B, 0x261D5190 */
const SB2: f64 = 3.25792512996573918826e+02; /* 0x40745CAE, 0x221B9F0A */
const SB3: f64 = 1.53672958608443695994e+03; /* 0x409802EB, 0x189D5118 */
const SB4: f64 = 3.19985821950859553908e+03; /* 0x40A8FFB7, 0x688C246A */
const SB5: f64 = 2.55305040643316442583e+03; /* 0x40A3F219, 0xCEDF3BE6 */
const SB6: f64 = 4.74528541206955367215e+02; /* 0x407DA874, 0xE79FE763 */
const SB7: f64 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */
fn erfc1(x: f64) -> f64 {
let s: f64;
let p: f64;
let q: f64;
s = fabs(x) - 1.0;
p = PA0 + s * (PA1 + s * (PA2 + s * (PA3 + s * (PA4 + s * (PA5 + s * PA6)))));
q = 1.0 + s * (QA1 + s * (QA2 + s * (QA3 + s * (QA4 + s * (QA5 + s * QA6)))));
1.0 - ERX - p / q
}
fn erfc2(ix: u32, mut x: f64) -> f64 {
let s: f64;
let r: f64;
let big_s: f64;
let z: f64;
if ix < 0x3ff40000 {
/* |x| < 1.25 */
return erfc1(x);
}
x = fabs(x);
s = 1.0 / (x * x);
if ix < 0x4006db6d {
/* |x| < 1/.35 ~ 2.85714 */
r = RA0 + s * (RA1 + s * (RA2 + s * (RA3 + s * (RA4 + s * (RA5 + s * (RA6 + s * RA7))))));
big_s = 1.0
+ s * (SA1
+ s * (SA2 + s * (SA3 + s * (SA4 + s * (SA5 + s * (SA6 + s * (SA7 + s * SA8)))))));
} else {
/* |x| > 1/.35 */
r = RB0 + s * (RB1 + s * (RB2 + s * (RB3 + s * (RB4 + s * (RB5 + s * RB6)))));
big_s =
1.0 + s * (SB1 + s * (SB2 + s * (SB3 + s * (SB4 + s * (SB5 + s * (SB6 + s * SB7))))));
}
z = with_set_low_word(x, 0);
exp(-z * z - 0.5625) * exp((z - x) * (z + x) + r / big_s) / x
}
/// Error function (f64)
///
/// Calculates an approximation to the “error function”, which estimates
/// the probability that an observation will fall within x standard
/// deviations of the mean (assuming a normal distribution).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn erf(x: f64) -> f64 {
let r: f64;
let s: f64;
let z: f64;
let y: f64;
let mut ix: u32;
let sign: usize;
ix = get_high_word(x);
sign = (ix >> 31) as usize;
ix &= 0x7fffffff;
if ix >= 0x7ff00000 {
/* erf(nan)=nan, erf(+-inf)=+-1 */
return 1.0 - 2.0 * (sign as f64) + 1.0 / x;
}
if ix < 0x3feb0000 {
/* |x| < 0.84375 */
if ix < 0x3e300000 {
/* |x| < 2**-28 */
/* avoid underflow */
return 0.125 * (8.0 * x + EFX8 * x);
}
z = x * x;
r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4)));
s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5))));
y = r / s;
return x + x * y;
}
if ix < 0x40180000 {
/* 0.84375 <= |x| < 6 */
y = 1.0 - erfc2(ix, x);
} else {
let x1p_1022 = f64::from_bits(0x0010000000000000);
y = 1.0 - x1p_1022;
}
if sign != 0 { -y } else { y }
}
/// Complementary error function (f64)
///
/// Calculates the complementary probability.
/// Is `1 - erf(x)`. Is computed directly, so that you can use it to avoid
/// the loss of precision that would result from subtracting
/// large probabilities (on large `x`) from 1.
pub fn erfc(x: f64) -> f64 {
let r: f64;
let s: f64;
let z: f64;
let y: f64;
let mut ix: u32;
let sign: usize;
ix = get_high_word(x);
sign = (ix >> 31) as usize;
ix &= 0x7fffffff;
if ix >= 0x7ff00000 {
/* erfc(nan)=nan, erfc(+-inf)=0,2 */
return 2.0 * (sign as f64) + 1.0 / x;
}
if ix < 0x3feb0000 {
/* |x| < 0.84375 */
if ix < 0x3c700000 {
/* |x| < 2**-56 */
return 1.0 - x;
}
z = x * x;
r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4)));
s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5))));
y = r / s;
if sign != 0 || ix < 0x3fd00000 {
/* x < 1/4 */
return 1.0 - (x + x * y);
}
return 0.5 - (x - 0.5 + x * y);
}
if ix < 0x403c0000 {
/* 0.84375 <= |x| < 28 */
if sign != 0 {
return 2.0 - erfc2(ix, x);
} else {
return erfc2(ix, x);
}
}
let x1p_1022 = f64::from_bits(0x0010000000000000);
if sign != 0 {
2.0 - x1p_1022
} else {
x1p_1022 * x1p_1022
}
}

226
vendor/libm/src/math/erff.rs vendored Normal file
View File

@@ -0,0 +1,226 @@
/* origin: FreeBSD /usr/src/lib/msun/src/s_erff.c */
/*
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
use super::{expf, fabsf};
const ERX: f32 = 8.4506291151e-01; /* 0x3f58560b */
/*
* Coefficients for approximation to erf on [0,0.84375]
*/
const EFX8: f32 = 1.0270333290e+00; /* 0x3f8375d4 */
const PP0: f32 = 1.2837916613e-01; /* 0x3e0375d4 */
const PP1: f32 = -3.2504209876e-01; /* 0xbea66beb */
const PP2: f32 = -2.8481749818e-02; /* 0xbce9528f */
const PP3: f32 = -5.7702702470e-03; /* 0xbbbd1489 */
const PP4: f32 = -2.3763017452e-05; /* 0xb7c756b1 */
const QQ1: f32 = 3.9791721106e-01; /* 0x3ecbbbce */
const QQ2: f32 = 6.5022252500e-02; /* 0x3d852a63 */
const QQ3: f32 = 5.0813062117e-03; /* 0x3ba68116 */
const QQ4: f32 = 1.3249473704e-04; /* 0x390aee49 */
const QQ5: f32 = -3.9602282413e-06; /* 0xb684e21a */
/*
* Coefficients for approximation to erf in [0.84375,1.25]
*/
const PA0: f32 = -2.3621185683e-03; /* 0xbb1acdc6 */
const PA1: f32 = 4.1485610604e-01; /* 0x3ed46805 */
const PA2: f32 = -3.7220788002e-01; /* 0xbebe9208 */
const PA3: f32 = 3.1834661961e-01; /* 0x3ea2fe54 */
const PA4: f32 = -1.1089469492e-01; /* 0xbde31cc2 */
const PA5: f32 = 3.5478305072e-02; /* 0x3d1151b3 */
const PA6: f32 = -2.1663755178e-03; /* 0xbb0df9c0 */
const QA1: f32 = 1.0642088205e-01; /* 0x3dd9f331 */
const QA2: f32 = 5.4039794207e-01; /* 0x3f0a5785 */
const QA3: f32 = 7.1828655899e-02; /* 0x3d931ae7 */
const QA4: f32 = 1.2617121637e-01; /* 0x3e013307 */
const QA5: f32 = 1.3637083583e-02; /* 0x3c5f6e13 */
const QA6: f32 = 1.1984500103e-02; /* 0x3c445aa3 */
/*
* Coefficients for approximation to erfc in [1.25,1/0.35]
*/
const RA0: f32 = -9.8649440333e-03; /* 0xbc21a093 */
const RA1: f32 = -6.9385856390e-01; /* 0xbf31a0b7 */
const RA2: f32 = -1.0558626175e+01; /* 0xc128f022 */
const RA3: f32 = -6.2375331879e+01; /* 0xc2798057 */
const RA4: f32 = -1.6239666748e+02; /* 0xc322658c */
const RA5: f32 = -1.8460508728e+02; /* 0xc3389ae7 */
const RA6: f32 = -8.1287437439e+01; /* 0xc2a2932b */
const RA7: f32 = -9.8143291473e+00; /* 0xc11d077e */
const SA1: f32 = 1.9651271820e+01; /* 0x419d35ce */
const SA2: f32 = 1.3765776062e+02; /* 0x4309a863 */
const SA3: f32 = 4.3456588745e+02; /* 0x43d9486f */
const SA4: f32 = 6.4538726807e+02; /* 0x442158c9 */
const SA5: f32 = 4.2900814819e+02; /* 0x43d6810b */
const SA6: f32 = 1.0863500214e+02; /* 0x42d9451f */
const SA7: f32 = 6.5702495575e+00; /* 0x40d23f7c */
const SA8: f32 = -6.0424413532e-02; /* 0xbd777f97 */
/*
* Coefficients for approximation to erfc in [1/.35,28]
*/
const RB0: f32 = -9.8649431020e-03; /* 0xbc21a092 */
const RB1: f32 = -7.9928326607e-01; /* 0xbf4c9dd4 */
const RB2: f32 = -1.7757955551e+01; /* 0xc18e104b */
const RB3: f32 = -1.6063638306e+02; /* 0xc320a2ea */
const RB4: f32 = -6.3756646729e+02; /* 0xc41f6441 */
const RB5: f32 = -1.0250950928e+03; /* 0xc480230b */
const RB6: f32 = -4.8351919556e+02; /* 0xc3f1c275 */
const SB1: f32 = 3.0338060379e+01; /* 0x41f2b459 */
const SB2: f32 = 3.2579251099e+02; /* 0x43a2e571 */
const SB3: f32 = 1.5367296143e+03; /* 0x44c01759 */
const SB4: f32 = 3.1998581543e+03; /* 0x4547fdbb */
const SB5: f32 = 2.5530502930e+03; /* 0x451f90ce */
const SB6: f32 = 4.7452853394e+02; /* 0x43ed43a7 */
const SB7: f32 = -2.2440952301e+01; /* 0xc1b38712 */
fn erfc1(x: f32) -> f32 {
let s: f32;
let p: f32;
let q: f32;
s = fabsf(x) - 1.0;
p = PA0 + s * (PA1 + s * (PA2 + s * (PA3 + s * (PA4 + s * (PA5 + s * PA6)))));
q = 1.0 + s * (QA1 + s * (QA2 + s * (QA3 + s * (QA4 + s * (QA5 + s * QA6)))));
return 1.0 - ERX - p / q;
}
fn erfc2(mut ix: u32, mut x: f32) -> f32 {
let s: f32;
let r: f32;
let big_s: f32;
let z: f32;
if ix < 0x3fa00000 {
/* |x| < 1.25 */
return erfc1(x);
}
x = fabsf(x);
s = 1.0 / (x * x);
if ix < 0x4036db6d {
/* |x| < 1/0.35 */
r = RA0 + s * (RA1 + s * (RA2 + s * (RA3 + s * (RA4 + s * (RA5 + s * (RA6 + s * RA7))))));
big_s = 1.0
+ s * (SA1
+ s * (SA2 + s * (SA3 + s * (SA4 + s * (SA5 + s * (SA6 + s * (SA7 + s * SA8)))))));
} else {
/* |x| >= 1/0.35 */
r = RB0 + s * (RB1 + s * (RB2 + s * (RB3 + s * (RB4 + s * (RB5 + s * RB6)))));
big_s =
1.0 + s * (SB1 + s * (SB2 + s * (SB3 + s * (SB4 + s * (SB5 + s * (SB6 + s * SB7))))));
}
ix = x.to_bits();
z = f32::from_bits(ix & 0xffffe000);
expf(-z * z - 0.5625) * expf((z - x) * (z + x) + r / big_s) / x
}
/// Error function (f32)
///
/// Calculates an approximation to the “error function”, which estimates
/// the probability that an observation will fall within x standard
/// deviations of the mean (assuming a normal distribution).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn erff(x: f32) -> f32 {
let r: f32;
let s: f32;
let z: f32;
let y: f32;
let mut ix: u32;
let sign: usize;
ix = x.to_bits();
sign = (ix >> 31) as usize;
ix &= 0x7fffffff;
if ix >= 0x7f800000 {
/* erf(nan)=nan, erf(+-inf)=+-1 */
return 1.0 - 2.0 * (sign as f32) + 1.0 / x;
}
if ix < 0x3f580000 {
/* |x| < 0.84375 */
if ix < 0x31800000 {
/* |x| < 2**-28 */
/*avoid underflow */
return 0.125 * (8.0 * x + EFX8 * x);
}
z = x * x;
r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4)));
s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5))));
y = r / s;
return x + x * y;
}
if ix < 0x40c00000 {
/* |x| < 6 */
y = 1.0 - erfc2(ix, x);
} else {
let x1p_120 = f32::from_bits(0x03800000);
y = 1.0 - x1p_120;
}
if sign != 0 { -y } else { y }
}
/// Complementary error function (f32)
///
/// Calculates the complementary probability.
/// Is `1 - erf(x)`. Is computed directly, so that you can use it to avoid
/// the loss of precision that would result from subtracting
/// large probabilities (on large `x`) from 1.
pub fn erfcf(x: f32) -> f32 {
let r: f32;
let s: f32;
let z: f32;
let y: f32;
let mut ix: u32;
let sign: usize;
ix = x.to_bits();
sign = (ix >> 31) as usize;
ix &= 0x7fffffff;
if ix >= 0x7f800000 {
/* erfc(nan)=nan, erfc(+-inf)=0,2 */
return 2.0 * (sign as f32) + 1.0 / x;
}
if ix < 0x3f580000 {
/* |x| < 0.84375 */
if ix < 0x23800000 {
/* |x| < 2**-56 */
return 1.0 - x;
}
z = x * x;
r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4)));
s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5))));
y = r / s;
if sign != 0 || ix < 0x3e800000 {
/* x < 1/4 */
return 1.0 - (x + x * y);
}
return 0.5 - (x - 0.5 + x * y);
}
if ix < 0x41e00000 {
/* |x| < 28 */
if sign != 0 {
return 2.0 - erfc2(ix, x);
} else {
return erfc2(ix, x);
}
}
let x1p_120 = f32::from_bits(0x03800000);
if sign != 0 {
2.0 - x1p_120
} else {
x1p_120 * x1p_120
}
}

150
vendor/libm/src/math/exp.rs vendored Normal file
View File

@@ -0,0 +1,150 @@
/* origin: FreeBSD /usr/src/lib/msun/src/e_exp.c */
/*
* ====================================================
* Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
*
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
/* exp(x)
* Returns the exponential of x.
*
* Method
* 1. Argument reduction:
* Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
* Given x, find r and integer k such that
*
* x = k*ln2 + r, |r| <= 0.5*ln2.
*
* Here r will be represented as r = hi-lo for better
* accuracy.
*
* 2. Approximation of exp(r) by a special rational function on
* the interval [0,0.34658]:
* Write
* R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
* We use a special Remez algorithm on [0,0.34658] to generate
* a polynomial of degree 5 to approximate R. The maximum error
* of this polynomial approximation is bounded by 2**-59. In
* other words,
* R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
* (where z=r*r, and the values of P1 to P5 are listed below)
* and
* | 5 | -59
* | 2.0+P1*z+...+P5*z - R(z) | <= 2
* | |
* The computation of exp(r) thus becomes
* 2*r
* exp(r) = 1 + ----------
* R(r) - r
* r*c(r)
* = 1 + r + ----------- (for better accuracy)
* 2 - c(r)
* where
* 2 4 10
* c(r) = r - (P1*r + P2*r + ... + P5*r ).
*
* 3. Scale back to obtain exp(x):
* From step 1, we have
* exp(x) = 2^k * exp(r)
*
* Special cases:
* exp(INF) is INF, exp(NaN) is NaN;
* exp(-INF) is 0, and
* for finite argument, only exp(0)=1 is exact.
*
* Accuracy:
* according to an error analysis, the error is always less than
* 1 ulp (unit in the last place).
*
* Misc. info.
* For IEEE double
* if x > 709.782712893383973096 then exp(x) overflows
* if x < -745.133219101941108420 then exp(x) underflows
*/
use super::scalbn;
const HALF: [f64; 2] = [0.5, -0.5];
const LN2HI: f64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */
const LN2LO: f64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */
const INVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */
const P1: f64 = 1.66666666666666019037e-01; /* 0x3FC55555, 0x5555553E */
const P2: f64 = -2.77777777770155933842e-03; /* 0xBF66C16C, 0x16BEBD93 */
const P3: f64 = 6.61375632143793436117e-05; /* 0x3F11566A, 0xAF25DE2C */
const P4: f64 = -1.65339022054652515390e-06; /* 0xBEBBBD41, 0xC5D26BF1 */
const P5: f64 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */
/// Exponential, base *e* (f64)
///
/// Calculate the exponential of `x`, that is, *e* raised to the power `x`
/// (where *e* is the base of the natural system of logarithms, approximately 2.71828).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn exp(mut x: f64) -> f64 {
let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023
let x1p_149 = f64::from_bits(0x36a0000000000000); // 0x1p-149 === 2 ^ -149
let hi: f64;
let lo: f64;
let c: f64;
let xx: f64;
let y: f64;
let k: i32;
let sign: i32;
let mut hx: u32;
hx = (x.to_bits() >> 32) as u32;
sign = (hx >> 31) as i32;
hx &= 0x7fffffff; /* high word of |x| */
/* special cases */
if hx >= 0x4086232b {
/* if |x| >= 708.39... */
if x.is_nan() {
return x;
}
if x > 709.782712893383973096 {
/* overflow if x!=inf */
x *= x1p1023;
return x;
}
if x < -708.39641853226410622 {
/* underflow if x!=-inf */
force_eval!((-x1p_149 / x) as f32);
if x < -745.13321910194110842 {
return 0.;
}
}
}
/* argument reduction */
if hx > 0x3fd62e42 {
/* if |x| > 0.5 ln2 */
if hx >= 0x3ff0a2b2 {
/* if |x| >= 1.5 ln2 */
k = (INVLN2 * x + i!(HALF, sign as usize)) as i32;
} else {
k = 1 - sign - sign;
}
hi = x - k as f64 * LN2HI; /* k*ln2hi is exact here */
lo = k as f64 * LN2LO;
x = hi - lo;
} else if hx > 0x3e300000 {
/* if |x| > 2**-28 */
k = 0;
hi = x;
lo = 0.;
} else {
/* inexact if x!=0 */
force_eval!(x1p1023 + x);
return 1. + x;
}
/* x is now in primary range */
xx = x * x;
c = x - xx * (P1 + xx * (P2 + xx * (P3 + xx * (P4 + xx * P5))));
y = 1. + (x * c / (2. - c) - lo + hi);
if k == 0 { y } else { scalbn(y, k) }
}

23
vendor/libm/src/math/exp10.rs vendored Normal file
View File

@@ -0,0 +1,23 @@
use super::{exp2, modf, pow};
const LN10: f64 = 3.32192809488736234787031942948939;
const P10: &[f64] = &[
1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1,
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
];
/// Calculates 10 raised to the power of `x` (f64).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn exp10(x: f64) -> f64 {
let (mut y, n) = modf(x);
let u: u64 = n.to_bits();
/* fabs(n) < 16 without raising invalid on nan */
if ((u >> 52) & 0x7ff) < 0x3ff + 4 {
if y == 0.0 {
return i!(P10, ((n as isize) + 15) as usize);
}
y = exp2(LN10 * y);
return y * i!(P10, ((n as isize) + 15) as usize);
}
return pow(10.0, x);
}

23
vendor/libm/src/math/exp10f.rs vendored Normal file
View File

@@ -0,0 +1,23 @@
use super::{exp2, exp2f, modff};
const LN10_F32: f32 = 3.32192809488736234787031942948939;
const LN10_F64: f64 = 3.32192809488736234787031942948939;
const P10: &[f32] = &[
1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
];
/// Calculates 10 raised to the power of `x` (f32).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn exp10f(x: f32) -> f32 {
let (mut y, n) = modff(x);
let u = n.to_bits();
/* fabsf(n) < 8 without raising invalid on nan */
if ((u >> 23) & 0xff) < 0x7f + 3 {
if y == 0.0 {
return i!(P10, ((n as isize) + 7) as usize);
}
y = exp2f(LN10_F32 * y);
return y * i!(P10, ((n as isize) + 7) as usize);
}
return exp2(LN10_F64 * (x as f64)) as f32;
}

394
vendor/libm/src/math/exp2.rs vendored Normal file
View File

@@ -0,0 +1,394 @@
// origin: FreeBSD /usr/src/lib/msun/src/s_exp2.c */
//-
// Copyright (c) 2005 David Schultz <das@FreeBSD.ORG>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
use super::scalbn;
const TBLSIZE: usize = 256;
#[rustfmt::skip]
static TBL: [u64; TBLSIZE * 2] = [
// exp2(z + eps) eps
0x3fe6a09e667f3d5d, 0x3d39880000000000,
0x3fe6b052fa751744, 0x3cd8000000000000,
0x3fe6c012750bd9fe, 0xbd28780000000000,
0x3fe6cfdcddd476bf, 0x3d1ec00000000000,
0x3fe6dfb23c651a29, 0xbcd8000000000000,
0x3fe6ef9298593ae3, 0xbcbc000000000000,
0x3fe6ff7df9519386, 0xbd2fd80000000000,
0x3fe70f7466f42da3, 0xbd2c880000000000,
0x3fe71f75e8ec5fc3, 0x3d13c00000000000,
0x3fe72f8286eacf05, 0xbd38300000000000,
0x3fe73f9a48a58152, 0xbd00c00000000000,
0x3fe74fbd35d7ccfc, 0x3d2f880000000000,
0x3fe75feb564267f1, 0x3d03e00000000000,
0x3fe77024b1ab6d48, 0xbd27d00000000000,
0x3fe780694fde5d38, 0xbcdd000000000000,
0x3fe790b938ac1d00, 0x3ce3000000000000,
0x3fe7a11473eb0178, 0xbced000000000000,
0x3fe7b17b0976d060, 0x3d20400000000000,
0x3fe7c1ed0130c133, 0x3ca0000000000000,
0x3fe7d26a62ff8636, 0xbd26900000000000,
0x3fe7e2f336cf4e3b, 0xbd02e00000000000,
0x3fe7f3878491c3e8, 0xbd24580000000000,
0x3fe80427543e1b4e, 0x3d33000000000000,
0x3fe814d2add1071a, 0x3d0f000000000000,
0x3fe82589994ccd7e, 0xbd21c00000000000,
0x3fe8364c1eb942d0, 0x3d29d00000000000,
0x3fe8471a4623cab5, 0x3d47100000000000,
0x3fe857f4179f5bbc, 0x3d22600000000000,
0x3fe868d99b4491af, 0xbd32c40000000000,
0x3fe879cad931a395, 0xbd23000000000000,
0x3fe88ac7d98a65b8, 0xbd2a800000000000,
0x3fe89bd0a4785800, 0xbced000000000000,
0x3fe8ace5422aa223, 0x3d33280000000000,
0x3fe8be05bad619fa, 0x3d42b40000000000,
0x3fe8cf3216b54383, 0xbd2ed00000000000,
0x3fe8e06a5e08664c, 0xbd20500000000000,
0x3fe8f1ae99157807, 0x3d28280000000000,
0x3fe902fed0282c0e, 0xbd1cb00000000000,
0x3fe9145b0b91ff96, 0xbd05e00000000000,
0x3fe925c353aa2ff9, 0x3cf5400000000000,
0x3fe93737b0cdc64a, 0x3d17200000000000,
0x3fe948b82b5f98ae, 0xbd09000000000000,
0x3fe95a44cbc852cb, 0x3d25680000000000,
0x3fe96bdd9a766f21, 0xbd36d00000000000,
0x3fe97d829fde4e2a, 0xbd01000000000000,
0x3fe98f33e47a23a3, 0x3d2d000000000000,
0x3fe9a0f170ca0604, 0xbd38a40000000000,
0x3fe9b2bb4d53ff89, 0x3d355c0000000000,
0x3fe9c49182a3f15b, 0x3d26b80000000000,
0x3fe9d674194bb8c5, 0xbcec000000000000,
0x3fe9e86319e3238e, 0x3d17d00000000000,
0x3fe9fa5e8d07f302, 0x3d16400000000000,
0x3fea0c667b5de54d, 0xbcf5000000000000,
0x3fea1e7aed8eb8f6, 0x3d09e00000000000,
0x3fea309bec4a2e27, 0x3d2ad80000000000,
0x3fea42c980460a5d, 0xbd1af00000000000,
0x3fea5503b23e259b, 0x3d0b600000000000,
0x3fea674a8af46213, 0x3d38880000000000,
0x3fea799e1330b3a7, 0x3d11200000000000,
0x3fea8bfe53c12e8d, 0x3d06c00000000000,
0x3fea9e6b5579fcd2, 0xbd29b80000000000,
0x3feab0e521356fb8, 0x3d2b700000000000,
0x3feac36bbfd3f381, 0x3cd9000000000000,
0x3fead5ff3a3c2780, 0x3ce4000000000000,
0x3feae89f995ad2a3, 0xbd2c900000000000,
0x3feafb4ce622f367, 0x3d16500000000000,
0x3feb0e07298db790, 0x3d2fd40000000000,
0x3feb20ce6c9a89a9, 0x3d12700000000000,
0x3feb33a2b84f1a4b, 0x3d4d470000000000,
0x3feb468415b747e7, 0xbd38380000000000,
0x3feb59728de5593a, 0x3c98000000000000,
0x3feb6c6e29f1c56a, 0x3d0ad00000000000,
0x3feb7f76f2fb5e50, 0x3cde800000000000,
0x3feb928cf22749b2, 0xbd04c00000000000,
0x3feba5b030a10603, 0xbd0d700000000000,
0x3febb8e0b79a6f66, 0x3d0d900000000000,
0x3febcc1e904bc1ff, 0x3d02a00000000000,
0x3febdf69c3f3a16f, 0xbd1f780000000000,
0x3febf2c25bd71db8, 0xbd10a00000000000,
0x3fec06286141b2e9, 0xbd11400000000000,
0x3fec199bdd8552e0, 0x3d0be00000000000,
0x3fec2d1cd9fa64ee, 0xbd09400000000000,
0x3fec40ab5fffd02f, 0xbd0ed00000000000,
0x3fec544778fafd15, 0x3d39660000000000,
0x3fec67f12e57d0cb, 0xbd1a100000000000,
0x3fec7ba88988c1b6, 0xbd58458000000000,
0x3fec8f6d9406e733, 0xbd1a480000000000,
0x3feca3405751c4df, 0x3ccb000000000000,
0x3fecb720dcef9094, 0x3d01400000000000,
0x3feccb0f2e6d1689, 0x3cf0200000000000,
0x3fecdf0b555dc412, 0x3cf3600000000000,
0x3fecf3155b5bab3b, 0xbd06900000000000,
0x3fed072d4a0789bc, 0x3d09a00000000000,
0x3fed1b532b08c8fa, 0xbd15e00000000000,
0x3fed2f87080d8a85, 0x3d1d280000000000,
0x3fed43c8eacaa203, 0x3d01a00000000000,
0x3fed5818dcfba491, 0x3cdf000000000000,
0x3fed6c76e862e6a1, 0xbd03a00000000000,
0x3fed80e316c9834e, 0xbd0cd80000000000,
0x3fed955d71ff6090, 0x3cf4c00000000000,
0x3feda9e603db32ae, 0x3cff900000000000,
0x3fedbe7cd63a8325, 0x3ce9800000000000,
0x3fedd321f301b445, 0xbcf5200000000000,
0x3fede7d5641c05bf, 0xbd1d700000000000,
0x3fedfc97337b9aec, 0xbd16140000000000,
0x3fee11676b197d5e, 0x3d0b480000000000,
0x3fee264614f5a3e7, 0x3d40ce0000000000,
0x3fee3b333b16ee5c, 0x3d0c680000000000,
0x3fee502ee78b3fb4, 0xbd09300000000000,
0x3fee653924676d68, 0xbce5000000000000,
0x3fee7a51fbc74c44, 0xbd07f80000000000,
0x3fee8f7977cdb726, 0xbcf3700000000000,
0x3feea4afa2a490e8, 0x3ce5d00000000000,
0x3feeb9f4867ccae4, 0x3d161a0000000000,
0x3feecf482d8e680d, 0x3cf5500000000000,
0x3feee4aaa2188514, 0x3cc6400000000000,
0x3feefa1bee615a13, 0xbcee800000000000,
0x3fef0f9c1cb64106, 0xbcfa880000000000,
0x3fef252b376bb963, 0xbd2c900000000000,
0x3fef3ac948dd7275, 0x3caa000000000000,
0x3fef50765b6e4524, 0xbcf4f00000000000,
0x3fef6632798844fd, 0x3cca800000000000,
0x3fef7bfdad9cbe38, 0x3cfabc0000000000,
0x3fef91d802243c82, 0xbcd4600000000000,
0x3fefa7c1819e908e, 0xbd0b0c0000000000,
0x3fefbdba3692d511, 0xbcc0e00000000000,
0x3fefd3c22b8f7194, 0xbd10de8000000000,
0x3fefe9d96b2a23ee, 0x3cee430000000000,
0x3ff0000000000000, 0x0,
0x3ff00b1afa5abcbe, 0xbcb3400000000000,
0x3ff0163da9fb3303, 0xbd12170000000000,
0x3ff02168143b0282, 0x3cba400000000000,
0x3ff02c9a3e77806c, 0x3cef980000000000,
0x3ff037d42e11bbca, 0xbcc7400000000000,
0x3ff04315e86e7f89, 0x3cd8300000000000,
0x3ff04e5f72f65467, 0xbd1a3f0000000000,
0x3ff059b0d315855a, 0xbd02840000000000,
0x3ff0650a0e3c1f95, 0x3cf1600000000000,
0x3ff0706b29ddf71a, 0x3d15240000000000,
0x3ff07bd42b72a82d, 0xbce9a00000000000,
0x3ff0874518759bd0, 0x3ce6400000000000,
0x3ff092bdf66607c8, 0xbd00780000000000,
0x3ff09e3ecac6f383, 0xbc98000000000000,
0x3ff0a9c79b1f3930, 0x3cffa00000000000,
0x3ff0b5586cf988fc, 0xbcfac80000000000,
0x3ff0c0f145e46c8a, 0x3cd9c00000000000,
0x3ff0cc922b724816, 0x3d05200000000000,
0x3ff0d83b23395dd8, 0xbcfad00000000000,
0x3ff0e3ec32d3d1f3, 0x3d1bac0000000000,
0x3ff0efa55fdfa9a6, 0xbd04e80000000000,
0x3ff0fb66affed2f0, 0xbd0d300000000000,
0x3ff1073028d7234b, 0x3cf1500000000000,
0x3ff11301d0125b5b, 0x3cec000000000000,
0x3ff11edbab5e2af9, 0x3d16bc0000000000,
0x3ff12abdc06c31d5, 0x3ce8400000000000,
0x3ff136a814f2047d, 0xbd0ed00000000000,
0x3ff1429aaea92de9, 0x3ce8e00000000000,
0x3ff14e95934f3138, 0x3ceb400000000000,
0x3ff15a98c8a58e71, 0x3d05300000000000,
0x3ff166a45471c3df, 0x3d03380000000000,
0x3ff172b83c7d5211, 0x3d28d40000000000,
0x3ff17ed48695bb9f, 0xbd05d00000000000,
0x3ff18af9388c8d93, 0xbd1c880000000000,
0x3ff1972658375d66, 0x3d11f00000000000,
0x3ff1a35beb6fcba7, 0x3d10480000000000,
0x3ff1af99f81387e3, 0xbd47390000000000,
0x3ff1bbe084045d54, 0x3d24e40000000000,
0x3ff1c82f95281c43, 0xbd0a200000000000,
0x3ff1d4873168b9b2, 0x3ce3800000000000,
0x3ff1e0e75eb44031, 0x3ceac00000000000,
0x3ff1ed5022fcd938, 0x3d01900000000000,
0x3ff1f9c18438cdf7, 0xbd1b780000000000,
0x3ff2063b88628d8f, 0x3d2d940000000000,
0x3ff212be3578a81e, 0x3cd8000000000000,
0x3ff21f49917ddd41, 0x3d2b340000000000,
0x3ff22bdda2791323, 0x3d19f80000000000,
0x3ff2387a6e7561e7, 0xbd19c80000000000,
0x3ff2451ffb821427, 0x3d02300000000000,
0x3ff251ce4fb2a602, 0xbd13480000000000,
0x3ff25e85711eceb0, 0x3d12700000000000,
0x3ff26b4565e27d16, 0x3d11d00000000000,
0x3ff2780e341de00f, 0x3d31ee0000000000,
0x3ff284dfe1f5633e, 0xbd14c00000000000,
0x3ff291ba7591bb30, 0xbd13d80000000000,
0x3ff29e9df51fdf09, 0x3d08b00000000000,
0x3ff2ab8a66d10e9b, 0xbd227c0000000000,
0x3ff2b87fd0dada3a, 0x3d2a340000000000,
0x3ff2c57e39771af9, 0xbd10800000000000,
0x3ff2d285a6e402d9, 0xbd0ed00000000000,
0x3ff2df961f641579, 0xbcf4200000000000,
0x3ff2ecafa93e2ecf, 0xbd24980000000000,
0x3ff2f9d24abd8822, 0xbd16300000000000,
0x3ff306fe0a31b625, 0xbd32360000000000,
0x3ff31432edeea50b, 0xbd70df8000000000,
0x3ff32170fc4cd7b8, 0xbd22480000000000,
0x3ff32eb83ba8e9a2, 0xbd25980000000000,
0x3ff33c08b2641766, 0x3d1ed00000000000,
0x3ff3496266e3fa27, 0xbcdc000000000000,
0x3ff356c55f929f0f, 0xbd30d80000000000,
0x3ff36431a2de88b9, 0x3d22c80000000000,
0x3ff371a7373aaa39, 0x3d20600000000000,
0x3ff37f26231e74fe, 0xbd16600000000000,
0x3ff38cae6d05d838, 0xbd0ae00000000000,
0x3ff39a401b713ec3, 0xbd44720000000000,
0x3ff3a7db34e5a020, 0x3d08200000000000,
0x3ff3b57fbfec6e95, 0x3d3e800000000000,
0x3ff3c32dc313a8f2, 0x3cef800000000000,
0x3ff3d0e544ede122, 0xbd17a00000000000,
0x3ff3dea64c1234bb, 0x3d26300000000000,
0x3ff3ec70df1c4ecc, 0xbd48a60000000000,
0x3ff3fa4504ac7e8c, 0xbd3cdc0000000000,
0x3ff40822c367a0bb, 0x3d25b80000000000,
0x3ff4160a21f72e95, 0x3d1ec00000000000,
0x3ff423fb27094646, 0xbd13600000000000,
0x3ff431f5d950a920, 0x3d23980000000000,
0x3ff43ffa3f84b9eb, 0x3cfa000000000000,
0x3ff44e0860618919, 0xbcf6c00000000000,
0x3ff45c2042a7d201, 0xbd0bc00000000000,
0x3ff46a41ed1d0016, 0xbd12800000000000,
0x3ff4786d668b3326, 0x3d30e00000000000,
0x3ff486a2b5c13c00, 0xbd2d400000000000,
0x3ff494e1e192af04, 0x3d0c200000000000,
0x3ff4a32af0d7d372, 0xbd1e500000000000,
0x3ff4b17dea6db801, 0x3d07800000000000,
0x3ff4bfdad53629e1, 0xbd13800000000000,
0x3ff4ce41b817c132, 0x3d00800000000000,
0x3ff4dcb299fddddb, 0x3d2c700000000000,
0x3ff4eb2d81d8ab96, 0xbd1ce00000000000,
0x3ff4f9b2769d2d02, 0x3d19200000000000,
0x3ff508417f4531c1, 0xbd08c00000000000,
0x3ff516daa2cf662a, 0xbcfa000000000000,
0x3ff5257de83f51ea, 0x3d4a080000000000,
0x3ff5342b569d4eda, 0xbd26d80000000000,
0x3ff542e2f4f6ac1a, 0xbd32440000000000,
0x3ff551a4ca5d94db, 0x3d483c0000000000,
0x3ff56070dde9116b, 0x3d24b00000000000,
0x3ff56f4736b529de, 0x3d415a0000000000,
0x3ff57e27dbe2c40e, 0xbd29e00000000000,
0x3ff58d12d497c76f, 0xbd23080000000000,
0x3ff59c0827ff0b4c, 0x3d4dec0000000000,
0x3ff5ab07dd485427, 0xbcc4000000000000,
0x3ff5ba11fba87af4, 0x3d30080000000000,
0x3ff5c9268a59460b, 0xbd26c80000000000,
0x3ff5d84590998e3f, 0x3d469a0000000000,
0x3ff5e76f15ad20e1, 0xbd1b400000000000,
0x3ff5f6a320dcebca, 0x3d17700000000000,
0x3ff605e1b976dcb8, 0x3d26f80000000000,
0x3ff6152ae6cdf715, 0x3d01000000000000,
0x3ff6247eb03a5531, 0xbd15d00000000000,
0x3ff633dd1d1929b5, 0xbd12d00000000000,
0x3ff6434634ccc313, 0xbcea800000000000,
0x3ff652b9febc8efa, 0xbd28600000000000,
0x3ff6623882553397, 0x3d71fe0000000000,
0x3ff671c1c708328e, 0xbd37200000000000,
0x3ff68155d44ca97e, 0x3ce6800000000000,
0x3ff690f4b19e9471, 0xbd29780000000000,
];
// exp2(x): compute the base 2 exponential of x
//
// Accuracy: Peak error < 0.503 ulp for normalized results.
//
// Method: (accurate tables)
//
// Reduce x:
// x = k + y, for integer k and |y| <= 1/2.
// Thus we have exp2(x) = 2**k * exp2(y).
//
// Reduce y:
// y = i/TBLSIZE + z - eps[i] for integer i near y * TBLSIZE.
// Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z - eps[i]),
// with |z - eps[i]| <= 2**-9 + 2**-39 for the table used.
//
// We compute exp2(i/TBLSIZE) via table lookup and exp2(z - eps[i]) via
// a degree-5 minimax polynomial with maximum error under 1.3 * 2**-61.
// The values in exp2t[] and eps[] are chosen such that
// exp2t[i] = exp2(i/TBLSIZE + eps[i]), and eps[i] is a small offset such
// that exp2t[i] is accurate to 2**-64.
//
// Note that the range of i is +-TBLSIZE/2, so we actually index the tables
// by i0 = i + TBLSIZE/2. For cache efficiency, exp2t[] and eps[] are
// virtual tables, interleaved in the real table tbl[].
//
// This method is due to Gal, with many details due to Gal and Bachelis:
//
// Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library
// for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991).
/// Exponential, base 2 (f64)
///
/// Calculate `2^x`, that is, 2 raised to the power `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn exp2(mut x: f64) -> f64 {
let redux = f64::from_bits(0x4338000000000000) / TBLSIZE as f64;
let p1 = f64::from_bits(0x3fe62e42fefa39ef);
let p2 = f64::from_bits(0x3fcebfbdff82c575);
let p3 = f64::from_bits(0x3fac6b08d704a0a6);
let p4 = f64::from_bits(0x3f83b2ab88f70400);
let p5 = f64::from_bits(0x3f55d88003875c74);
// double_t r, t, z;
// uint32_t ix, i0;
// union {double f; uint64_t i;} u = {x};
// union {uint32_t u; int32_t i;} k;
let x1p1023 = f64::from_bits(0x7fe0000000000000);
let x1p52 = f64::from_bits(0x4330000000000000);
let _0x1p_149 = f64::from_bits(0xb6a0000000000000);
/* Filter out exceptional cases. */
let ui = f64::to_bits(x);
let ix = (ui >> 32) & 0x7fffffff;
if ix >= 0x408ff000 {
/* |x| >= 1022 or nan */
if ix >= 0x40900000 && ui >> 63 == 0 {
/* x >= 1024 or nan */
/* overflow */
x *= x1p1023;
return x;
}
if ix >= 0x7ff00000 {
/* -inf or -nan */
return -1.0 / x;
}
if ui >> 63 != 0 {
/* x <= -1022 */
/* underflow */
if x <= -1075.0 || x - x1p52 + x1p52 != x {
force_eval!((_0x1p_149 / x) as f32);
}
if x <= -1075.0 {
return 0.0;
}
}
} else if ix < 0x3c900000 {
/* |x| < 0x1p-54 */
return 1.0 + x;
}
/* Reduce x, computing z, i0, and k. */
let ui = f64::to_bits(x + redux);
let mut i0 = ui as u32;
i0 = i0.wrapping_add(TBLSIZE as u32 / 2);
let ku = i0 / TBLSIZE as u32 * TBLSIZE as u32;
let ki = div!(ku as i32, TBLSIZE as i32);
i0 %= TBLSIZE as u32;
let uf = f64::from_bits(ui) - redux;
let mut z = x - uf;
/* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */
let t = f64::from_bits(i!(TBL, 2 * i0 as usize)); /* exp2t[i0] */
z -= f64::from_bits(i!(TBL, 2 * i0 as usize + 1)); /* eps[i0] */
let r = t + t * z * (p1 + z * (p2 + z * (p3 + z * (p4 + z * p5))));
scalbn(r, ki)
}
#[test]
fn i0_wrap_test() {
let x = -3.0 / 256.0;
assert_eq!(exp2(x), f64::from_bits(0x3fefbdba3692d514));
}

135
vendor/libm/src/math/exp2f.rs vendored Normal file
View File

@@ -0,0 +1,135 @@
// origin: FreeBSD /usr/src/lib/msun/src/s_exp2f.c
//-
// Copyright (c) 2005 David Schultz <das@FreeBSD.ORG>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
const TBLSIZE: usize = 16;
static EXP2FT: [u64; TBLSIZE] = [
0x3fe6a09e667f3bcd,
0x3fe7a11473eb0187,
0x3fe8ace5422aa0db,
0x3fe9c49182a3f090,
0x3feae89f995ad3ad,
0x3fec199bdd85529c,
0x3fed5818dcfba487,
0x3feea4afa2a490da,
0x3ff0000000000000,
0x3ff0b5586cf9890f,
0x3ff172b83c7d517b,
0x3ff2387a6e756238,
0x3ff306fe0a31b715,
0x3ff3dea64c123422,
0x3ff4bfdad5362a27,
0x3ff5ab07dd485429,
];
// exp2f(x): compute the base 2 exponential of x
//
// Accuracy: Peak error < 0.501 ulp; location of peak: -0.030110927.
//
// Method: (equally-spaced tables)
//
// Reduce x:
// x = k + y, for integer k and |y| <= 1/2.
// Thus we have exp2f(x) = 2**k * exp2(y).
//
// Reduce y:
// y = i/TBLSIZE + z for integer i near y * TBLSIZE.
// Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z),
// with |z| <= 2**-(TBLSIZE+1).
//
// We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a
// degree-4 minimax polynomial with maximum error under 1.4 * 2**-33.
// Using double precision for everything except the reduction makes
// roundoff error insignificant and simplifies the scaling step.
//
// This method is due to Tang, but I do not use his suggested parameters:
//
// Tang, P. Table-driven Implementation of the Exponential Function
// in IEEE Floating-Point Arithmetic. TOMS 15(2), 144-157 (1989).
/// Exponential, base 2 (f32)
///
/// Calculate `2^x`, that is, 2 raised to the power `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn exp2f(mut x: f32) -> f32 {
let redux = f32::from_bits(0x4b400000) / TBLSIZE as f32;
let p1 = f32::from_bits(0x3f317218);
let p2 = f32::from_bits(0x3e75fdf0);
let p3 = f32::from_bits(0x3d6359a4);
let p4 = f32::from_bits(0x3c1d964e);
// double_t t, r, z;
// uint32_t ix, i0, k;
let x1p127 = f32::from_bits(0x7f000000);
/* Filter out exceptional cases. */
let ui = f32::to_bits(x);
let ix = ui & 0x7fffffff;
if ix > 0x42fc0000 {
/* |x| > 126 */
if ix > 0x7f800000 {
/* NaN */
return x;
}
if (0x43000000..0x80000000).contains(&ui) {
/* x >= 128 */
x *= x1p127;
return x;
}
if ui >= 0x80000000 {
/* x < -126 */
if ui >= 0xc3160000 || (ui & 0x0000ffff != 0) {
force_eval!(f32::from_bits(0x80000001) / x);
}
if ui >= 0xc3160000 {
/* x <= -150 */
return 0.0;
}
}
} else if ix <= 0x33000000 {
/* |x| <= 0x1p-25 */
return 1.0 + x;
}
/* Reduce x, computing z, i0, and k. */
let ui = f32::to_bits(x + redux);
let mut i0 = ui;
i0 += TBLSIZE as u32 / 2;
let k = i0 / TBLSIZE as u32;
let ukf = f64::from_bits(((0x3ff + k) as u64) << 52);
i0 &= TBLSIZE as u32 - 1;
let mut uf = f32::from_bits(ui);
uf -= redux;
let z: f64 = (x - uf) as f64;
/* Compute r = exp2(y) = exp2ft[i0] * p(z). */
let r: f64 = f64::from_bits(i!(EXP2FT, i0 as usize));
let t: f64 = r * z;
let r: f64 = r + t * (p1 as f64 + z * p2 as f64) + t * (z * z) * (p3 as f64 + z * p4 as f64);
/* Scale by 2**k */
(r * ukf) as f32
}

97
vendor/libm/src/math/expf.rs vendored Normal file
View File

@@ -0,0 +1,97 @@
/* origin: FreeBSD /usr/src/lib/msun/src/e_expf.c */
/*
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
use super::scalbnf;
const HALF: [f32; 2] = [0.5, -0.5];
const LN2_HI: f32 = 6.9314575195e-01; /* 0x3f317200 */
const LN2_LO: f32 = 1.4286067653e-06; /* 0x35bfbe8e */
const INV_LN2: f32 = 1.4426950216e+00; /* 0x3fb8aa3b */
/*
* Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]:
* |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74
*/
const P1: f32 = 1.6666625440e-1; /* 0xaaaa8f.0p-26 */
const P2: f32 = -2.7667332906e-3; /* -0xb55215.0p-32 */
/// Exponential, base *e* (f32)
///
/// Calculate the exponential of `x`, that is, *e* raised to the power `x`
/// (where *e* is the base of the natural system of logarithms, approximately 2.71828).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn expf(mut x: f32) -> f32 {
let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127
let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 /*original 0x1p-149f ??????????? */
let mut hx = x.to_bits();
let sign = (hx >> 31) as i32; /* sign bit of x */
let signb: bool = sign != 0;
hx &= 0x7fffffff; /* high word of |x| */
/* special cases */
if hx >= 0x42aeac50 {
/* if |x| >= -87.33655f or NaN */
if hx > 0x7f800000 {
/* NaN */
return x;
}
if (hx >= 0x42b17218) && (!signb) {
/* x >= 88.722839f */
/* overflow */
x *= x1p127;
return x;
}
if signb {
/* underflow */
force_eval!(-x1p_126 / x);
if hx >= 0x42cff1b5 {
/* x <= -103.972084f */
return 0.;
}
}
}
/* argument reduction */
let k: i32;
let hi: f32;
let lo: f32;
if hx > 0x3eb17218 {
/* if |x| > 0.5 ln2 */
if hx > 0x3f851592 {
/* if |x| > 1.5 ln2 */
k = (INV_LN2 * x + i!(HALF, sign as usize)) as i32;
} else {
k = 1 - sign - sign;
}
let kf = k as f32;
hi = x - kf * LN2_HI; /* k*ln2hi is exact here */
lo = kf * LN2_LO;
x = hi - lo;
} else if hx > 0x39000000 {
/* |x| > 2**-14 */
k = 0;
hi = x;
lo = 0.;
} else {
/* raise inexact */
force_eval!(x1p127 + x);
return 1. + x;
}
/* x is now in primary range */
let xx = x * x;
let c = x - xx * (P1 + xx * P2);
let y = 1. + (x * c / (2. - c) - lo + hi);
if k == 0 { y } else { scalbnf(y, k) }
}

144
vendor/libm/src/math/expm1.rs vendored Normal file
View File

@@ -0,0 +1,144 @@
/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1.c */
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
use core::f64;
const O_THRESHOLD: f64 = 7.09782712893383973096e+02; /* 0x40862E42, 0xFEFA39EF */
const LN2_HI: f64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */
const LN2_LO: f64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */
const INVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */
/* Scaled Q's: Qn_here = 2**n * Qn_above, for R(2*z) where z = hxs = x*x/2: */
const Q1: f64 = -3.33333333333331316428e-02; /* BFA11111 111110F4 */
const Q2: f64 = 1.58730158725481460165e-03; /* 3F5A01A0 19FE5585 */
const Q3: f64 = -7.93650757867487942473e-05; /* BF14CE19 9EAADBB7 */
const Q4: f64 = 4.00821782732936239552e-06; /* 3ED0CFCA 86E65239 */
const Q5: f64 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */
/// Exponential, base *e*, of x-1 (f64)
///
/// Calculates the exponential of `x` and subtract 1, that is, *e* raised
/// to the power `x` minus 1 (where *e* is the base of the natural
/// system of logarithms, approximately 2.71828).
/// The result is accurate even for small values of `x`,
/// where using `exp(x)-1` would lose many significant digits.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn expm1(mut x: f64) -> f64 {
let hi: f64;
let lo: f64;
let k: i32;
let c: f64;
let mut t: f64;
let mut y: f64;
let mut ui = x.to_bits();
let hx = ((ui >> 32) & 0x7fffffff) as u32;
let sign = (ui >> 63) as i32;
/* filter out huge and non-finite argument */
if hx >= 0x4043687A {
/* if |x|>=56*ln2 */
if x.is_nan() {
return x;
}
if sign != 0 {
return -1.0;
}
if x > O_THRESHOLD {
x *= f64::from_bits(0x7fe0000000000000);
return x;
}
}
/* argument reduction */
if hx > 0x3fd62e42 {
/* if |x| > 0.5 ln2 */
if hx < 0x3FF0A2B2 {
/* and |x| < 1.5 ln2 */
if sign == 0 {
hi = x - LN2_HI;
lo = LN2_LO;
k = 1;
} else {
hi = x + LN2_HI;
lo = -LN2_LO;
k = -1;
}
} else {
k = (INVLN2 * x + if sign != 0 { -0.5 } else { 0.5 }) as i32;
t = k as f64;
hi = x - t * LN2_HI; /* t*ln2_hi is exact here */
lo = t * LN2_LO;
}
x = hi - lo;
c = (hi - x) - lo;
} else if hx < 0x3c900000 {
/* |x| < 2**-54, return x */
if hx < 0x00100000 {
force_eval!(x);
}
return x;
} else {
c = 0.0;
k = 0;
}
/* x is now in primary range */
let hfx = 0.5 * x;
let hxs = x * hfx;
let r1 = 1.0 + hxs * (Q1 + hxs * (Q2 + hxs * (Q3 + hxs * (Q4 + hxs * Q5))));
t = 3.0 - r1 * hfx;
let mut e = hxs * ((r1 - t) / (6.0 - x * t));
if k == 0 {
/* c is 0 */
return x - (x * e - hxs);
}
e = x * (e - c) - c;
e -= hxs;
/* exp(x) ~ 2^k (x_reduced - e + 1) */
if k == -1 {
return 0.5 * (x - e) - 0.5;
}
if k == 1 {
if x < -0.25 {
return -2.0 * (e - (x + 0.5));
}
return 1.0 + 2.0 * (x - e);
}
ui = ((0x3ff + k) as u64) << 52; /* 2^k */
let twopk = f64::from_bits(ui);
if !(0..=56).contains(&k) {
/* suffice to return exp(x)-1 */
y = x - e + 1.0;
if k == 1024 {
y = y * 2.0 * f64::from_bits(0x7fe0000000000000);
} else {
y = y * twopk;
}
return y - 1.0;
}
ui = ((0x3ff - k) as u64) << 52; /* 2^-k */
let uf = f64::from_bits(ui);
if k < 20 {
y = (x - e + (1.0 - uf)) * twopk;
} else {
y = (x - (e + uf) + 1.0) * twopk;
}
y
}
#[cfg(test)]
mod tests {
#[test]
fn sanity_check() {
assert_eq!(super::expm1(1.1), 2.0041660239464334);
}
}

134
vendor/libm/src/math/expm1f.rs vendored Normal file
View File

@@ -0,0 +1,134 @@
/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1f.c */
/*
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
const O_THRESHOLD: f32 = 8.8721679688e+01; /* 0x42b17180 */
const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */
const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */
const INV_LN2: f32 = 1.4426950216e+00; /* 0x3fb8aa3b */
/*
* Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]:
* |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04
* Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c):
*/
const Q1: f32 = -3.3333212137e-2; /* -0x888868.0p-28 */
const Q2: f32 = 1.5807170421e-3; /* 0xcf3010.0p-33 */
/// Exponential, base *e*, of x-1 (f32)
///
/// Calculates the exponential of `x` and subtract 1, that is, *e* raised
/// to the power `x` minus 1 (where *e* is the base of the natural
/// system of logarithms, approximately 2.71828).
/// The result is accurate even for small values of `x`,
/// where using `exp(x)-1` would lose many significant digits.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn expm1f(mut x: f32) -> f32 {
let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127
let mut hx = x.to_bits();
let sign = (hx >> 31) != 0;
hx &= 0x7fffffff;
/* filter out huge and non-finite argument */
if hx >= 0x4195b844 {
/* if |x|>=27*ln2 */
if hx > 0x7f800000 {
/* NaN */
return x;
}
if sign {
return -1.;
}
if x > O_THRESHOLD {
x *= x1p127;
return x;
}
}
let k: i32;
let hi: f32;
let lo: f32;
let mut c = 0f32;
/* argument reduction */
if hx > 0x3eb17218 {
/* if |x| > 0.5 ln2 */
if hx < 0x3F851592 {
/* and |x| < 1.5 ln2 */
if !sign {
hi = x - LN2_HI;
lo = LN2_LO;
k = 1;
} else {
hi = x + LN2_HI;
lo = -LN2_LO;
k = -1;
}
} else {
k = (INV_LN2 * x + (if sign { -0.5 } else { 0.5 })) as i32;
let t = k as f32;
hi = x - t * LN2_HI; /* t*ln2_hi is exact here */
lo = t * LN2_LO;
}
x = hi - lo;
c = (hi - x) - lo;
} else if hx < 0x33000000 {
/* when |x|<2**-25, return x */
if hx < 0x00800000 {
force_eval!(x * x);
}
return x;
} else {
k = 0;
}
/* x is now in primary range */
let hfx = 0.5 * x;
let hxs = x * hfx;
let r1 = 1. + hxs * (Q1 + hxs * Q2);
let t = 3. - r1 * hfx;
let mut e = hxs * ((r1 - t) / (6. - x * t));
if k == 0 {
/* c is 0 */
return x - (x * e - hxs);
}
e = x * (e - c) - c;
e -= hxs;
/* exp(x) ~ 2^k (x_reduced - e + 1) */
if k == -1 {
return 0.5 * (x - e) - 0.5;
}
if k == 1 {
if x < -0.25 {
return -2. * (e - (x + 0.5));
}
return 1. + 2. * (x - e);
}
let twopk = f32::from_bits(((0x7f + k) << 23) as u32); /* 2^k */
if !(0..=56).contains(&k) {
/* suffice to return exp(x)-1 */
let mut y = x - e + 1.;
if k == 128 {
y = y * 2. * x1p127;
} else {
y = y * twopk;
}
return y - 1.;
}
let uf = f32::from_bits(((0x7f - k) << 23) as u32); /* 2^-k */
if k < 23 {
(x - e + (1. - uf)) * twopk
} else {
(x - (e + uf) + 1.) * twopk
}
}

14
vendor/libm/src/math/expo2.rs vendored Normal file
View File

@@ -0,0 +1,14 @@
use super::{combine_words, exp};
/* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub(crate) fn expo2(x: f64) -> f64 {
/* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */
const K: i32 = 2043;
let kln2 = f64::from_bits(0x40962066151add8b);
/* note that k is odd and scale*scale overflows */
let scale = combine_words(((0x3ff + K / 2) as u32) << 20, 0);
/* exp(x - k ln2) * 2**(k-1) */
exp(x - kln2) * scale * scale
}

116
vendor/libm/src/math/fabs.rs vendored Normal file
View File

@@ -0,0 +1,116 @@
/// Absolute value (magnitude) (f16)
///
/// Calculates the absolute value (magnitude) of the argument `x`,
/// by direct manipulation of the bit representation of `x`.
#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fabsf16(x: f16) -> f16 {
super::generic::fabs(x)
}
/// Absolute value (magnitude) (f32)
///
/// Calculates the absolute value (magnitude) of the argument `x`,
/// by direct manipulation of the bit representation of `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fabsf(x: f32) -> f32 {
select_implementation! {
name: fabsf,
use_arch: all(target_arch = "wasm32", intrinsics_enabled),
args: x,
}
super::generic::fabs(x)
}
/// Absolute value (magnitude) (f64)
///
/// Calculates the absolute value (magnitude) of the argument `x`,
/// by direct manipulation of the bit representation of `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fabs(x: f64) -> f64 {
select_implementation! {
name: fabs,
use_arch: all(target_arch = "wasm32", intrinsics_enabled),
args: x,
}
super::generic::fabs(x)
}
/// Absolute value (magnitude) (f128)
///
/// Calculates the absolute value (magnitude) of the argument `x`,
/// by direct manipulation of the bit representation of `x`.
#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fabsf128(x: f128) -> f128 {
super::generic::fabs(x)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::support::Float;
/// Based on https://en.cppreference.com/w/cpp/numeric/math/fabs
fn spec_test<F: Float>(f: impl Fn(F) -> F) {
assert_biteq!(f(F::ZERO), F::ZERO);
assert_biteq!(f(F::NEG_ZERO), F::ZERO);
assert_biteq!(f(F::INFINITY), F::INFINITY);
assert_biteq!(f(F::NEG_INFINITY), F::INFINITY);
assert!(f(F::NAN).is_nan());
// Not spec rewquired but we expect it
assert!(f(F::NAN).is_sign_positive());
assert!(f(F::from_bits(F::NAN.to_bits() | F::SIGN_MASK)).is_sign_positive());
}
#[test]
#[cfg(f16_enabled)]
fn sanity_check_f16() {
assert_eq!(fabsf16(-1.0f16), 1.0);
assert_eq!(fabsf16(2.8f16), 2.8);
}
#[test]
#[cfg(f16_enabled)]
fn spec_tests_f16() {
spec_test::<f16>(fabsf16);
}
#[test]
fn sanity_check_f32() {
assert_eq!(fabsf(-1.0f32), 1.0);
assert_eq!(fabsf(2.8f32), 2.8);
}
#[test]
fn spec_tests_f32() {
spec_test::<f32>(fabsf);
}
#[test]
fn sanity_check_f64() {
assert_eq!(fabs(-1.0f64), 1.0);
assert_eq!(fabs(2.8f64), 2.8);
}
#[test]
fn spec_tests_f64() {
spec_test::<f64>(fabs);
}
#[test]
#[cfg(f128_enabled)]
fn sanity_check_f128() {
assert_eq!(fabsf128(-1.0f128), 1.0);
assert_eq!(fabsf128(2.8f128), 2.8);
}
#[test]
#[cfg(f128_enabled)]
fn spec_tests_f128() {
spec_test::<f128>(fabsf128);
}
}

39
vendor/libm/src/math/fabsf.rs vendored Normal file
View File

@@ -0,0 +1,39 @@
/// Absolute value (magnitude) (f32)
///
/// Calculates the absolute value (magnitude) of the argument `x`,
/// by direct manipulation of the bit representation of `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fabsf(x: f32) -> f32 {
select_implementation! {
name: fabsf,
use_arch: all(target_arch = "wasm32", intrinsics_enabled),
args: x,
}
super::generic::fabs(x)
}
// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520
#[cfg(not(target_arch = "powerpc64"))]
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sanity_check() {
assert_eq!(fabsf(-1.0), 1.0);
assert_eq!(fabsf(2.8), 2.8);
}
/// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs
#[test]
fn spec_tests() {
assert!(fabsf(f32::NAN).is_nan());
for f in [0.0, -0.0].iter().copied() {
assert_eq!(fabsf(f), 0.0);
}
for f in [f32::INFINITY, f32::NEG_INFINITY].iter().copied() {
assert_eq!(fabsf(f), f32::INFINITY);
}
}
}

31
vendor/libm/src/math/fabsf128.rs vendored Normal file
View File

@@ -0,0 +1,31 @@
/// Absolute value (magnitude) (f128)
///
/// Calculates the absolute value (magnitude) of the argument `x`,
/// by direct manipulation of the bit representation of `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fabsf128(x: f128) -> f128 {
super::generic::fabs(x)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sanity_check() {
assert_eq!(fabsf128(-1.0), 1.0);
assert_eq!(fabsf128(2.8), 2.8);
}
/// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs
#[test]
fn spec_tests() {
assert!(fabsf128(f128::NAN).is_nan());
for f in [0.0, -0.0].iter().copied() {
assert_eq!(fabsf128(f), 0.0);
}
for f in [f128::INFINITY, f128::NEG_INFINITY].iter().copied() {
assert_eq!(fabsf128(f), f128::INFINITY);
}
}
}

31
vendor/libm/src/math/fabsf16.rs vendored Normal file
View File

@@ -0,0 +1,31 @@
/// Absolute value (magnitude) (f16)
///
/// Calculates the absolute value (magnitude) of the argument `x`,
/// by direct manipulation of the bit representation of `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fabsf16(x: f16) -> f16 {
super::generic::fabs(x)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sanity_check() {
assert_eq!(fabsf16(-1.0), 1.0);
assert_eq!(fabsf16(2.8), 2.8);
}
/// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs
#[test]
fn spec_tests() {
assert!(fabsf16(f16::NAN).is_nan());
for f in [0.0, -0.0].iter().copied() {
assert_eq!(fabsf16(f), 0.0);
}
for f in [f16::INFINITY, f16::NEG_INFINITY].iter().copied() {
assert_eq!(fabsf16(f), f16::INFINITY);
}
}
}

53
vendor/libm/src/math/fdim.rs vendored Normal file
View File

@@ -0,0 +1,53 @@
/// Positive difference (f16)
///
/// Determines the positive difference between arguments, returning:
/// * x - y if x > y, or
/// * +0 if x <= y, or
/// * NAN if either argument is NAN.
///
/// A range error may occur.
#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fdimf16(x: f16, y: f16) -> f16 {
super::generic::fdim(x, y)
}
/// Positive difference (f32)
///
/// Determines the positive difference between arguments, returning:
/// * x - y if x > y, or
/// * +0 if x <= y, or
/// * NAN if either argument is NAN.
///
/// A range error may occur.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fdimf(x: f32, y: f32) -> f32 {
super::generic::fdim(x, y)
}
/// Positive difference (f64)
///
/// Determines the positive difference between arguments, returning:
/// * x - y if x > y, or
/// * +0 if x <= y, or
/// * NAN if either argument is NAN.
///
/// A range error may occur.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fdim(x: f64, y: f64) -> f64 {
super::generic::fdim(x, y)
}
/// Positive difference (f128)
///
/// Determines the positive difference between arguments, returning:
/// * x - y if x > y, or
/// * +0 if x <= y, or
/// * NAN if either argument is NAN.
///
/// A range error may occur.
#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fdimf128(x: f128, y: f128) -> f128 {
super::generic::fdim(x, y)
}

12
vendor/libm/src/math/fdimf.rs vendored Normal file
View File

@@ -0,0 +1,12 @@
/// Positive difference (f32)
///
/// Determines the positive difference between arguments, returning:
/// * x - y if x > y, or
/// * +0 if x <= y, or
/// * NAN if either argument is NAN.
///
/// A range error may occur.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fdimf(x: f32, y: f32) -> f32 {
super::generic::fdim(x, y)
}

12
vendor/libm/src/math/fdimf128.rs vendored Normal file
View File

@@ -0,0 +1,12 @@
/// Positive difference (f128)
///
/// Determines the positive difference between arguments, returning:
/// * x - y if x > y, or
/// * +0 if x <= y, or
/// * NAN if either argument is NAN.
///
/// A range error may occur.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fdimf128(x: f128, y: f128) -> f128 {
super::generic::fdim(x, y)
}

12
vendor/libm/src/math/fdimf16.rs vendored Normal file
View File

@@ -0,0 +1,12 @@
/// Positive difference (f16)
///
/// Determines the positive difference between arguments, returning:
/// * x - y if x > y, or
/// * +0 if x <= y, or
/// * NAN if either argument is NAN.
///
/// A range error may occur.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fdimf16(x: f16, y: f16) -> f16 {
super::generic::fdim(x, y)
}

46
vendor/libm/src/math/floor.rs vendored Normal file
View File

@@ -0,0 +1,46 @@
/// Floor (f16)
///
/// Finds the nearest integer less than or equal to `x`.
#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn floorf16(x: f16) -> f16 {
return super::generic::floor(x);
}
/// Floor (f64)
///
/// Finds the nearest integer less than or equal to `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn floor(x: f64) -> f64 {
select_implementation! {
name: floor,
use_arch: all(target_arch = "wasm32", intrinsics_enabled),
use_arch_required: all(target_arch = "x86", not(target_feature = "sse2")),
args: x,
}
return super::generic::floor(x);
}
/// Floor (f32)
///
/// Finds the nearest integer less than or equal to `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn floorf(x: f32) -> f32 {
select_implementation! {
name: floorf,
use_arch: all(target_arch = "wasm32", intrinsics_enabled),
args: x,
}
return super::generic::floor(x);
}
/// Floor (f128)
///
/// Finds the nearest integer less than or equal to `x`.
#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn floorf128(x: f128) -> f128 {
return super::generic::floor(x);
}

13
vendor/libm/src/math/floorf.rs vendored Normal file
View File

@@ -0,0 +1,13 @@
/// Floor (f32)
///
/// Finds the nearest integer less than or equal to `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn floorf(x: f32) -> f32 {
select_implementation! {
name: floorf,
use_arch: all(target_arch = "wasm32", intrinsics_enabled),
args: x,
}
return super::generic::floor(x);
}

7
vendor/libm/src/math/floorf128.rs vendored Normal file
View File

@@ -0,0 +1,7 @@
/// Floor (f128)
///
/// Finds the nearest integer less than or equal to `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn floorf128(x: f128) -> f128 {
return super::generic::floor(x);
}

7
vendor/libm/src/math/floorf16.rs vendored Normal file
View File

@@ -0,0 +1,7 @@
/// Floor (f16)
///
/// Finds the nearest integer less than or equal to `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn floorf16(x: f16) -> f16 {
return super::generic::floor(x);
}

171
vendor/libm/src/math/fma.rs vendored Normal file
View File

@@ -0,0 +1,171 @@
/* SPDX-License-Identifier: MIT */
/* origin: musl src/math/fma.c, fmaf.c Ported to generic Rust algorithm in 2025, TG. */
use super::generic;
use crate::support::Round;
// Placeholder so we can have `fmaf16` in the `Float` trait.
#[allow(unused)]
#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub(crate) fn fmaf16(_x: f16, _y: f16, _z: f16) -> f16 {
unimplemented!()
}
/// Floating multiply add (f32)
///
/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fmaf(x: f32, y: f32, z: f32) -> f32 {
select_implementation! {
name: fmaf,
use_arch: any(
all(target_arch = "aarch64", target_feature = "neon"),
target_feature = "sse2",
),
args: x, y, z,
}
generic::fma_wide_round(x, y, z, Round::Nearest).val
}
/// Fused multiply add (f64)
///
/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fma(x: f64, y: f64, z: f64) -> f64 {
select_implementation! {
name: fma,
use_arch: any(
all(target_arch = "aarch64", target_feature = "neon"),
target_feature = "sse2",
),
args: x, y, z,
}
generic::fma_round(x, y, z, Round::Nearest).val
}
/// Fused multiply add (f128)
///
/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision).
#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fmaf128(x: f128, y: f128, z: f128) -> f128 {
generic::fma_round(x, y, z, Round::Nearest).val
}
#[cfg(test)]
mod tests {
use super::*;
use crate::support::{CastFrom, CastInto, Float, FpResult, HInt, MinInt, Round, Status};
/// Test the generic `fma_round` algorithm for a given float.
fn spec_test<F>(f: impl Fn(F, F, F) -> F)
where
F: Float,
F: CastFrom<F::SignedInt>,
F: CastFrom<i8>,
F::Int: HInt,
u32: CastInto<F::Int>,
{
let x = F::from_bits(F::Int::ONE);
let y = F::from_bits(F::Int::ONE);
let z = F::ZERO;
// 754-2020 says "When the exact result of (a × b) + c is non-zero yet the result of
// fusedMultiplyAdd is zero because of rounding, the zero result takes the sign of the
// exact result"
assert_biteq!(f(x, y, z), F::ZERO);
assert_biteq!(f(x, -y, z), F::NEG_ZERO);
assert_biteq!(f(-x, y, z), F::NEG_ZERO);
assert_biteq!(f(-x, -y, z), F::ZERO);
}
#[test]
fn spec_test_f32() {
spec_test::<f32>(fmaf);
// Also do a small check that the non-widening version works for f32 (this should ideally
// get tested some more).
spec_test::<f32>(|x, y, z| generic::fma_round(x, y, z, Round::Nearest).val);
}
#[test]
fn spec_test_f64() {
spec_test::<f64>(fma);
let expect_underflow = [
(
hf64!("0x1.0p-1070"),
hf64!("0x1.0p-1070"),
hf64!("0x1.ffffffffffffp-1023"),
hf64!("0x0.ffffffffffff8p-1022"),
),
(
// FIXME: we raise underflow but this should only be inexact (based on C and
// `rustc_apfloat`).
hf64!("0x1.0p-1070"),
hf64!("0x1.0p-1070"),
hf64!("-0x1.0p-1022"),
hf64!("-0x1.0p-1022"),
),
];
for (x, y, z, res) in expect_underflow {
let FpResult { val, status } = generic::fma_round(x, y, z, Round::Nearest);
assert_biteq!(val, res);
assert_eq!(status, Status::UNDERFLOW);
}
}
#[test]
#[cfg(f128_enabled)]
fn spec_test_f128() {
spec_test::<f128>(fmaf128);
}
#[test]
fn issue_263() {
let a = f32::from_bits(1266679807);
let b = f32::from_bits(1300234242);
let c = f32::from_bits(1115553792);
let expected = f32::from_bits(1501560833);
assert_eq!(fmaf(a, b, c), expected);
}
#[test]
fn fma_segfault() {
// These two inputs cause fma to segfault on release due to overflow:
assert_eq!(
fma(
-0.0000000000000002220446049250313,
-0.0000000000000002220446049250313,
-0.0000000000000002220446049250313
),
-0.00000000000000022204460492503126,
);
let result = fma(-0.992, -0.992, -0.992);
//force rounding to storage format on x87 to prevent superious errors.
#[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]
let result = force_eval!(result);
assert_eq!(result, -0.007936000000000007,);
}
#[test]
fn fma_sbb() {
assert_eq!(
fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN),
-3991680619069439e277
);
}
#[test]
fn fma_underflow() {
assert_eq!(
fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320),
0.0,
);
}
}

167
vendor/libm/src/math/fmin_fmax.rs vendored Normal file
View File

@@ -0,0 +1,167 @@
/// Return the lesser of two arguments or, if either argument is NaN, the other argument.
///
/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if
/// the inputs are -0.0 and +0.0, either may be returned).
#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fminf16(x: f16, y: f16) -> f16 {
super::generic::fmin(x, y)
}
/// Return the lesser of two arguments or, if either argument is NaN, the other argument.
///
/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if
/// the inputs are -0.0 and +0.0, either may be returned).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fminf(x: f32, y: f32) -> f32 {
super::generic::fmin(x, y)
}
/// Return the lesser of two arguments or, if either argument is NaN, the other argument.
///
/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if
/// the inputs are -0.0 and +0.0, either may be returned).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fmin(x: f64, y: f64) -> f64 {
super::generic::fmin(x, y)
}
/// Return the lesser of two arguments or, if either argument is NaN, the other argument.
///
/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if
/// the inputs are -0.0 and +0.0, either may be returned).
#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fminf128(x: f128, y: f128) -> f128 {
super::generic::fmin(x, y)
}
/// Return the greater of two arguments or, if either argument is NaN, the other argument.
///
/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if
/// the inputs are -0.0 and +0.0, either may be returned).
#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fmaxf16(x: f16, y: f16) -> f16 {
super::generic::fmax(x, y)
}
/// Return the greater of two arguments or, if either argument is NaN, the other argument.
///
/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if
/// the inputs are -0.0 and +0.0, either may be returned).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fmaxf(x: f32, y: f32) -> f32 {
super::generic::fmax(x, y)
}
/// Return the greater of two arguments or, if either argument is NaN, the other argument.
///
/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if
/// the inputs are -0.0 and +0.0, either may be returned).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fmax(x: f64, y: f64) -> f64 {
super::generic::fmax(x, y)
}
/// Return the greater of two arguments or, if either argument is NaN, the other argument.
///
/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if
/// the inputs are -0.0 and +0.0, either may be returned).
#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fmaxf128(x: f128, y: f128) -> f128 {
super::generic::fmax(x, y)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::support::{Float, Hexf};
fn fmin_spec_test<F: Float>(f: impl Fn(F, F) -> F) {
let cases = [
(F::ZERO, F::ZERO, F::ZERO),
(F::ONE, F::ONE, F::ONE),
(F::ZERO, F::ONE, F::ZERO),
(F::ONE, F::ZERO, F::ZERO),
(F::ZERO, F::NEG_ONE, F::NEG_ONE),
(F::NEG_ONE, F::ZERO, F::NEG_ONE),
(F::INFINITY, F::ZERO, F::ZERO),
(F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY),
(F::NAN, F::ZERO, F::ZERO),
(F::ZERO, F::NAN, F::ZERO),
(F::NAN, F::NAN, F::NAN),
];
for (x, y, res) in cases {
let val = f(x, y);
assert_biteq!(val, res, "fmin({}, {})", Hexf(x), Hexf(y));
}
}
#[test]
#[cfg(f16_enabled)]
fn fmin_spec_tests_f16() {
fmin_spec_test::<f16>(fminf16);
}
#[test]
fn fmin_spec_tests_f32() {
fmin_spec_test::<f32>(fminf);
}
#[test]
fn fmin_spec_tests_f64() {
fmin_spec_test::<f64>(fmin);
}
#[test]
#[cfg(f128_enabled)]
fn fmin_spec_tests_f128() {
fmin_spec_test::<f128>(fminf128);
}
fn fmax_spec_test<F: Float>(f: impl Fn(F, F) -> F) {
let cases = [
(F::ZERO, F::ZERO, F::ZERO),
(F::ONE, F::ONE, F::ONE),
(F::ZERO, F::ONE, F::ONE),
(F::ONE, F::ZERO, F::ONE),
(F::ZERO, F::NEG_ONE, F::ZERO),
(F::NEG_ONE, F::ZERO, F::ZERO),
(F::INFINITY, F::ZERO, F::INFINITY),
(F::NEG_INFINITY, F::ZERO, F::ZERO),
(F::NAN, F::ZERO, F::ZERO),
(F::ZERO, F::NAN, F::ZERO),
(F::NAN, F::NAN, F::NAN),
];
for (x, y, res) in cases {
let val = f(x, y);
assert_biteq!(val, res, "fmax({}, {})", Hexf(x), Hexf(y));
}
}
#[test]
#[cfg(f16_enabled)]
fn fmax_spec_tests_f16() {
fmax_spec_test::<f16>(fmaxf16);
}
#[test]
fn fmax_spec_tests_f32() {
fmax_spec_test::<f32>(fmaxf);
}
#[test]
fn fmax_spec_tests_f64() {
fmax_spec_test::<f64>(fmax);
}
#[test]
#[cfg(f128_enabled)]
fn fmax_spec_tests_f128() {
fmax_spec_test::<f128>(fmaxf128);
}
}

View File

@@ -0,0 +1,163 @@
/// Return the lesser of two arguments or, if either argument is NaN, the other argument.
///
/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0.
#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fminimumf16(x: f16, y: f16) -> f16 {
super::generic::fminimum(x, y)
}
/// Return the lesser of two arguments or, if either argument is NaN, the other argument.
///
/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fminimum(x: f64, y: f64) -> f64 {
super::generic::fminimum(x, y)
}
/// Return the lesser of two arguments or, if either argument is NaN, the other argument.
///
/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fminimumf(x: f32, y: f32) -> f32 {
super::generic::fminimum(x, y)
}
/// Return the lesser of two arguments or, if either argument is NaN, the other argument.
///
/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0.
#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fminimumf128(x: f128, y: f128) -> f128 {
super::generic::fminimum(x, y)
}
/// Return the greater of two arguments or, if either argument is NaN, the other argument.
///
/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0.
#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fmaximumf16(x: f16, y: f16) -> f16 {
super::generic::fmaximum(x, y)
}
/// Return the greater of two arguments or, if either argument is NaN, the other argument.
///
/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fmaximumf(x: f32, y: f32) -> f32 {
super::generic::fmaximum(x, y)
}
/// Return the greater of two arguments or, if either argument is NaN, the other argument.
///
/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fmaximum(x: f64, y: f64) -> f64 {
super::generic::fmaximum(x, y)
}
/// Return the greater of two arguments or, if either argument is NaN, the other argument.
///
/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0.
#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fmaximumf128(x: f128, y: f128) -> f128 {
super::generic::fmaximum(x, y)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::support::{Float, Hexf};
fn fminimum_spec_test<F: Float>(f: impl Fn(F, F) -> F) {
let cases = [
(F::ZERO, F::ZERO, F::ZERO),
(F::ONE, F::ONE, F::ONE),
(F::ZERO, F::ONE, F::ZERO),
(F::ONE, F::ZERO, F::ZERO),
(F::ZERO, F::NEG_ONE, F::NEG_ONE),
(F::NEG_ONE, F::ZERO, F::NEG_ONE),
(F::INFINITY, F::ZERO, F::ZERO),
(F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY),
(F::NAN, F::ZERO, F::NAN),
(F::ZERO, F::NAN, F::NAN),
(F::NAN, F::NAN, F::NAN),
(F::ZERO, F::NEG_ZERO, F::NEG_ZERO),
(F::NEG_ZERO, F::ZERO, F::NEG_ZERO),
];
for (x, y, res) in cases {
let val = f(x, y);
assert_biteq!(val, res, "fminimum({}, {})", Hexf(x), Hexf(y));
}
}
#[test]
#[cfg(f16_enabled)]
fn fminimum_spec_tests_f16() {
fminimum_spec_test::<f16>(fminimumf16);
}
#[test]
fn fminimum_spec_tests_f32() {
fminimum_spec_test::<f32>(fminimumf);
}
#[test]
fn fminimum_spec_tests_f64() {
fminimum_spec_test::<f64>(fminimum);
}
#[test]
#[cfg(f128_enabled)]
fn fminimum_spec_tests_f128() {
fminimum_spec_test::<f128>(fminimumf128);
}
fn fmaximum_spec_test<F: Float>(f: impl Fn(F, F) -> F) {
let cases = [
(F::ZERO, F::ZERO, F::ZERO),
(F::ONE, F::ONE, F::ONE),
(F::ZERO, F::ONE, F::ONE),
(F::ONE, F::ZERO, F::ONE),
(F::ZERO, F::NEG_ONE, F::ZERO),
(F::NEG_ONE, F::ZERO, F::ZERO),
(F::INFINITY, F::ZERO, F::INFINITY),
(F::NEG_INFINITY, F::ZERO, F::ZERO),
(F::NAN, F::ZERO, F::NAN),
(F::ZERO, F::NAN, F::NAN),
(F::NAN, F::NAN, F::NAN),
(F::ZERO, F::NEG_ZERO, F::ZERO),
(F::NEG_ZERO, F::ZERO, F::ZERO),
];
for (x, y, res) in cases {
let val = f(x, y);
assert_biteq!(val, res, "fmaximum({}, {})", Hexf(x), Hexf(y));
}
}
#[test]
#[cfg(f16_enabled)]
fn fmaximum_spec_tests_f16() {
fmaximum_spec_test::<f16>(fmaximumf16);
}
#[test]
fn fmaximum_spec_tests_f32() {
fmaximum_spec_test::<f32>(fmaximumf);
}
#[test]
fn fmaximum_spec_tests_f64() {
fmaximum_spec_test::<f64>(fmaximum);
}
#[test]
#[cfg(f128_enabled)]
fn fmaximum_spec_tests_f128() {
fmaximum_spec_test::<f128>(fmaximumf128);
}
}

View File

@@ -0,0 +1,163 @@
/// Return the lesser of two arguments or, if either argument is NaN, NaN.
///
/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0.
#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fminimum_numf16(x: f16, y: f16) -> f16 {
super::generic::fminimum_num(x, y)
}
/// Return the lesser of two arguments or, if either argument is NaN, NaN.
///
/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fminimum_numf(x: f32, y: f32) -> f32 {
super::generic::fminimum_num(x, y)
}
/// Return the lesser of two arguments or, if either argument is NaN, NaN.
///
/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fminimum_num(x: f64, y: f64) -> f64 {
super::generic::fminimum_num(x, y)
}
/// Return the lesser of two arguments or, if either argument is NaN, NaN.
///
/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0.
#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fminimum_numf128(x: f128, y: f128) -> f128 {
super::generic::fminimum_num(x, y)
}
/// Return the greater of two arguments or, if either argument is NaN, NaN.
///
/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0.
#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fmaximum_numf16(x: f16, y: f16) -> f16 {
super::generic::fmaximum_num(x, y)
}
/// Return the greater of two arguments or, if either argument is NaN, NaN.
///
/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fmaximum_numf(x: f32, y: f32) -> f32 {
super::generic::fmaximum_num(x, y)
}
/// Return the greater of two arguments or, if either argument is NaN, NaN.
///
/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fmaximum_num(x: f64, y: f64) -> f64 {
super::generic::fmaximum_num(x, y)
}
/// Return the greater of two arguments or, if either argument is NaN, NaN.
///
/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0.
#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fmaximum_numf128(x: f128, y: f128) -> f128 {
super::generic::fmaximum_num(x, y)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::support::{Float, Hexf};
fn fminimum_num_spec_test<F: Float>(f: impl Fn(F, F) -> F) {
let cases = [
(F::ZERO, F::ZERO, F::ZERO),
(F::ONE, F::ONE, F::ONE),
(F::ZERO, F::ONE, F::ZERO),
(F::ONE, F::ZERO, F::ZERO),
(F::ZERO, F::NEG_ONE, F::NEG_ONE),
(F::NEG_ONE, F::ZERO, F::NEG_ONE),
(F::INFINITY, F::ZERO, F::ZERO),
(F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY),
(F::NAN, F::ZERO, F::ZERO),
(F::ZERO, F::NAN, F::ZERO),
(F::NAN, F::NAN, F::NAN),
(F::ZERO, F::NEG_ZERO, F::NEG_ZERO),
(F::NEG_ZERO, F::ZERO, F::NEG_ZERO),
];
for (x, y, res) in cases {
let val = f(x, y);
assert_biteq!(val, res, "fminimum_num({}, {})", Hexf(x), Hexf(y));
}
}
#[test]
#[cfg(f16_enabled)]
fn fminimum_num_spec_tests_f16() {
fminimum_num_spec_test::<f16>(fminimum_numf16);
}
#[test]
fn fminimum_num_spec_tests_f32() {
fminimum_num_spec_test::<f32>(fminimum_numf);
}
#[test]
fn fminimum_num_spec_tests_f64() {
fminimum_num_spec_test::<f64>(fminimum_num);
}
#[test]
#[cfg(f128_enabled)]
fn fminimum_num_spec_tests_f128() {
fminimum_num_spec_test::<f128>(fminimum_numf128);
}
fn fmaximum_num_spec_test<F: Float>(f: impl Fn(F, F) -> F) {
let cases = [
(F::ZERO, F::ZERO, F::ZERO),
(F::ONE, F::ONE, F::ONE),
(F::ZERO, F::ONE, F::ONE),
(F::ONE, F::ZERO, F::ONE),
(F::ZERO, F::NEG_ONE, F::ZERO),
(F::NEG_ONE, F::ZERO, F::ZERO),
(F::INFINITY, F::ZERO, F::INFINITY),
(F::NEG_INFINITY, F::ZERO, F::ZERO),
(F::NAN, F::ZERO, F::ZERO),
(F::ZERO, F::NAN, F::ZERO),
(F::NAN, F::NAN, F::NAN),
(F::ZERO, F::NEG_ZERO, F::ZERO),
(F::NEG_ZERO, F::ZERO, F::ZERO),
];
for (x, y, res) in cases {
let val = f(x, y);
assert_biteq!(val, res, "fmaximum_num({}, {})", Hexf(x), Hexf(y));
}
}
#[test]
#[cfg(f16_enabled)]
fn fmaximum_num_spec_tests_f16() {
fmaximum_num_spec_test::<f16>(fmaximum_numf16);
}
#[test]
fn fmaximum_num_spec_tests_f32() {
fmaximum_num_spec_test::<f32>(fmaximum_numf);
}
#[test]
fn fmaximum_num_spec_tests_f64() {
fmaximum_num_spec_test::<f64>(fmaximum_num);
}
#[test]
#[cfg(f128_enabled)]
fn fmaximum_num_spec_tests_f128() {
fmaximum_num_spec_test::<f128>(fmaximum_numf128);
}
}

25
vendor/libm/src/math/fmod.rs vendored Normal file
View File

@@ -0,0 +1,25 @@
/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`.
#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fmodf16(x: f16, y: f16) -> f16 {
super::generic::fmod(x, y)
}
/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fmodf(x: f32, y: f32) -> f32 {
super::generic::fmod(x, y)
}
/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fmod(x: f64, y: f64) -> f64 {
super::generic::fmod(x, y)
}
/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`.
#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fmodf128(x: f128, y: f128) -> f128 {
super::generic::fmod(x, y)
}

5
vendor/libm/src/math/fmodf.rs vendored Normal file
View File

@@ -0,0 +1,5 @@
/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fmodf(x: f32, y: f32) -> f32 {
super::generic::fmod(x, y)
}

5
vendor/libm/src/math/fmodf128.rs vendored Normal file
View File

@@ -0,0 +1,5 @@
/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fmodf128(x: f128, y: f128) -> f128 {
super::generic::fmod(x, y)
}

5
vendor/libm/src/math/fmodf16.rs vendored Normal file
View File

@@ -0,0 +1,5 @@
/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fmodf16(x: f16, y: f16) -> f16 {
super::generic::fmod(x, y)
}

21
vendor/libm/src/math/frexp.rs vendored Normal file
View File

@@ -0,0 +1,21 @@
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn frexp(x: f64) -> (f64, i32) {
let mut y = x.to_bits();
let ee = ((y >> 52) & 0x7ff) as i32;
if ee == 0 {
if x != 0.0 {
let x1p64 = f64::from_bits(0x43f0000000000000);
let (x, e) = frexp(x * x1p64);
return (x, e - 64);
}
return (x, 0);
} else if ee == 0x7ff {
return (x, 0);
}
let e = ee - 0x3fe;
y &= 0x800fffffffffffff;
y |= 0x3fe0000000000000;
return (f64::from_bits(y), e);
}

22
vendor/libm/src/math/frexpf.rs vendored Normal file
View File

@@ -0,0 +1,22 @@
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn frexpf(x: f32) -> (f32, i32) {
let mut y = x.to_bits();
let ee: i32 = ((y >> 23) & 0xff) as i32;
if ee == 0 {
if x != 0.0 {
let x1p64 = f32::from_bits(0x5f800000);
let (x, e) = frexpf(x * x1p64);
return (x, e - 64);
} else {
return (x, 0);
}
} else if ee == 0xff {
return (x, 0);
}
let e = ee - 0x7e;
y &= 0x807fffff;
y |= 0x3f000000;
(f32::from_bits(y), e)
}

174
vendor/libm/src/math/generic/ceil.rs vendored Normal file
View File

@@ -0,0 +1,174 @@
/* SPDX-License-Identifier: MIT */
/* origin: musl src/math/ceilf.c */
//! Generic `ceil` algorithm.
//!
//! Note that this uses the algorithm from musl's `ceilf` rather than `ceil` or `ceill` because
//! performance seems to be better (based on icount) and it does not seem to experience rounding
//! errors on i386.
use crate::support::{Float, FpResult, Int, IntTy, MinInt, Status};
#[inline]
pub fn ceil<F: Float>(x: F) -> F {
ceil_status(x).val
}
#[inline]
pub fn ceil_status<F: Float>(x: F) -> FpResult<F> {
let zero = IntTy::<F>::ZERO;
let mut ix = x.to_bits();
let e = x.exp_unbiased();
// If the represented value has no fractional part, no truncation is needed.
if e >= F::SIG_BITS as i32 {
return FpResult::ok(x);
}
let status;
let res = if e >= 0 {
// |x| >= 1.0
let m = F::SIG_MASK >> e.unsigned();
if (ix & m) == zero {
// Portion to be masked is already zero; no adjustment needed.
return FpResult::ok(x);
}
// Otherwise, raise an inexact exception.
status = Status::INEXACT;
if x.is_sign_positive() {
ix += m;
}
ix &= !m;
F::from_bits(ix)
} else {
// |x| < 1.0, raise an inexact exception since truncation will happen (unless x == 0).
if ix & F::SIG_MASK == F::Int::ZERO {
status = Status::OK;
} else {
status = Status::INEXACT;
}
if x.is_sign_negative() {
// -1.0 < x <= -0.0; rounding up goes toward -0.0.
F::NEG_ZERO
} else if ix << 1 != zero {
// 0.0 < x < 1.0; rounding up goes toward +1.0.
F::ONE
} else {
// +0.0 remains unchanged
x
}
};
FpResult::new(res, status)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::support::Hexf;
/// Test against https://en.cppreference.com/w/cpp/numeric/math/ceil
fn spec_test<F: Float>(cases: &[(F, F, Status)]) {
let roundtrip = [
F::ZERO,
F::ONE,
F::NEG_ONE,
F::NEG_ZERO,
F::INFINITY,
F::NEG_INFINITY,
];
for x in roundtrip {
let FpResult { val, status } = ceil_status(x);
assert_biteq!(val, x, "{}", Hexf(x));
assert_eq!(status, Status::OK, "{}", Hexf(x));
}
for &(x, res, res_stat) in cases {
let FpResult { val, status } = ceil_status(x);
assert_biteq!(val, res, "{}", Hexf(x));
assert_eq!(status, res_stat, "{}", Hexf(x));
}
}
/* Skipping f16 / f128 "sanity_check"s due to rejected literal lexing at MSRV */
#[test]
#[cfg(f16_enabled)]
fn spec_tests_f16() {
let cases = [
(0.1, 1.0, Status::INEXACT),
(-0.1, -0.0, Status::INEXACT),
(0.9, 1.0, Status::INEXACT),
(-0.9, -0.0, Status::INEXACT),
(1.1, 2.0, Status::INEXACT),
(-1.1, -1.0, Status::INEXACT),
(1.9, 2.0, Status::INEXACT),
(-1.9, -1.0, Status::INEXACT),
];
spec_test::<f16>(&cases);
}
#[test]
fn sanity_check_f32() {
assert_eq!(ceil(1.1f32), 2.0);
assert_eq!(ceil(2.9f32), 3.0);
}
#[test]
fn spec_tests_f32() {
let cases = [
(0.1, 1.0, Status::INEXACT),
(-0.1, -0.0, Status::INEXACT),
(0.9, 1.0, Status::INEXACT),
(-0.9, -0.0, Status::INEXACT),
(1.1, 2.0, Status::INEXACT),
(-1.1, -1.0, Status::INEXACT),
(1.9, 2.0, Status::INEXACT),
(-1.9, -1.0, Status::INEXACT),
];
spec_test::<f32>(&cases);
}
#[test]
fn sanity_check_f64() {
assert_eq!(ceil(1.1f64), 2.0);
assert_eq!(ceil(2.9f64), 3.0);
}
#[test]
fn spec_tests_f64() {
let cases = [
(0.1, 1.0, Status::INEXACT),
(-0.1, -0.0, Status::INEXACT),
(0.9, 1.0, Status::INEXACT),
(-0.9, -0.0, Status::INEXACT),
(1.1, 2.0, Status::INEXACT),
(-1.1, -1.0, Status::INEXACT),
(1.9, 2.0, Status::INEXACT),
(-1.9, -1.0, Status::INEXACT),
];
spec_test::<f64>(&cases);
}
#[test]
#[cfg(f128_enabled)]
fn spec_tests_f128() {
let cases = [
(0.1, 1.0, Status::INEXACT),
(-0.1, -0.0, Status::INEXACT),
(0.9, 1.0, Status::INEXACT),
(-0.9, -0.0, Status::INEXACT),
(1.1, 2.0, Status::INEXACT),
(-1.1, -1.0, Status::INEXACT),
(1.9, 2.0, Status::INEXACT),
(-1.9, -1.0, Status::INEXACT),
];
spec_test::<f128>(&cases);
}
}

View File

@@ -0,0 +1,11 @@
use crate::support::Float;
/// Copy the sign of `y` to `x`.
#[inline]
pub fn copysign<F: Float>(x: F, y: F) -> F {
let mut ux = x.to_bits();
let uy = y.to_bits();
ux &= !F::SIGN_MASK;
ux |= uy & F::SIGN_MASK;
F::from_bits(ux)
}

8
vendor/libm/src/math/generic/fabs.rs vendored Normal file
View File

@@ -0,0 +1,8 @@
use crate::support::Float;
/// Absolute value.
#[inline]
pub fn fabs<F: Float>(x: F) -> F {
let abs_mask = !F::SIGN_MASK;
F::from_bits(x.to_bits() & abs_mask)
}

6
vendor/libm/src/math/generic/fdim.rs vendored Normal file
View File

@@ -0,0 +1,6 @@
use crate::support::Float;
#[inline]
pub fn fdim<F: Float>(x: F, y: F) -> F {
if x <= y { F::ZERO } else { x - y }
}

157
vendor/libm/src/math/generic/floor.rs vendored Normal file
View File

@@ -0,0 +1,157 @@
/* SPDX-License-Identifier: MIT
* origin: musl src/math/floor.c */
//! Generic `floor` algorithm.
//!
//! Note that this uses the algorithm from musl's `floorf` rather than `floor` or `floorl` because
//! performance seems to be better (based on icount) and it does not seem to experience rounding
//! errors on i386.
use crate::support::{Float, FpResult, Int, IntTy, MinInt, Status};
#[inline]
pub fn floor<F: Float>(x: F) -> F {
floor_status(x).val
}
#[inline]
pub fn floor_status<F: Float>(x: F) -> FpResult<F> {
let zero = IntTy::<F>::ZERO;
let mut ix = x.to_bits();
let e = x.exp_unbiased();
// If the represented value has no fractional part, no truncation is needed.
if e >= F::SIG_BITS as i32 {
return FpResult::ok(x);
}
let status;
let res = if e >= 0 {
// |x| >= 1.0
let m = F::SIG_MASK >> e.unsigned();
if ix & m == zero {
// Portion to be masked is already zero; no adjustment needed.
return FpResult::ok(x);
}
// Otherwise, raise an inexact exception.
status = Status::INEXACT;
if x.is_sign_negative() {
ix += m;
}
ix &= !m;
F::from_bits(ix)
} else {
// |x| < 1.0, raise an inexact exception since truncation will happen.
if ix & F::SIG_MASK == F::Int::ZERO {
status = Status::OK;
} else {
status = Status::INEXACT;
}
if x.is_sign_positive() {
// 0.0 <= x < 1.0; rounding down goes toward +0.0.
F::ZERO
} else if ix << 1 != zero {
// -1.0 < x < 0.0; rounding down goes toward -1.0.
F::NEG_ONE
} else {
// -0.0 remains unchanged
x
}
};
FpResult::new(res, status)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::support::Hexf;
/// Test against https://en.cppreference.com/w/cpp/numeric/math/floor
fn spec_test<F: Float>(cases: &[(F, F, Status)]) {
let roundtrip = [
F::ZERO,
F::ONE,
F::NEG_ONE,
F::NEG_ZERO,
F::INFINITY,
F::NEG_INFINITY,
];
for x in roundtrip {
let FpResult { val, status } = floor_status(x);
assert_biteq!(val, x, "{}", Hexf(x));
assert_eq!(status, Status::OK, "{}", Hexf(x));
}
for &(x, res, res_stat) in cases {
let FpResult { val, status } = floor_status(x);
assert_biteq!(val, res, "{}", Hexf(x));
assert_eq!(status, res_stat, "{}", Hexf(x));
}
}
/* Skipping f16 / f128 "sanity_check"s and spec cases due to rejected literal lexing at MSRV */
#[test]
#[cfg(f16_enabled)]
fn spec_tests_f16() {
let cases = [];
spec_test::<f16>(&cases);
}
#[test]
fn sanity_check_f32() {
assert_eq!(floor(0.5f32), 0.0);
assert_eq!(floor(1.1f32), 1.0);
assert_eq!(floor(2.9f32), 2.0);
}
#[test]
fn spec_tests_f32() {
let cases = [
(0.1, 0.0, Status::INEXACT),
(-0.1, -1.0, Status::INEXACT),
(0.9, 0.0, Status::INEXACT),
(-0.9, -1.0, Status::INEXACT),
(1.1, 1.0, Status::INEXACT),
(-1.1, -2.0, Status::INEXACT),
(1.9, 1.0, Status::INEXACT),
(-1.9, -2.0, Status::INEXACT),
];
spec_test::<f32>(&cases);
}
#[test]
fn sanity_check_f64() {
assert_eq!(floor(1.1f64), 1.0);
assert_eq!(floor(2.9f64), 2.0);
}
#[test]
fn spec_tests_f64() {
let cases = [
(0.1, 0.0, Status::INEXACT),
(-0.1, -1.0, Status::INEXACT),
(0.9, 0.0, Status::INEXACT),
(-0.9, -1.0, Status::INEXACT),
(1.1, 1.0, Status::INEXACT),
(-1.1, -2.0, Status::INEXACT),
(1.9, 1.0, Status::INEXACT),
(-1.9, -2.0, Status::INEXACT),
];
spec_test::<f64>(&cases);
}
#[test]
#[cfg(f128_enabled)]
fn spec_tests_f128() {
let cases = [];
spec_test::<f128>(&cases);
}
}

278
vendor/libm/src/math/generic/fma.rs vendored Normal file
View File

@@ -0,0 +1,278 @@
/* SPDX-License-Identifier: MIT */
/* origin: musl src/math/fma.c. Ported to generic Rust algorithm in 2025, TG. */
use crate::support::{
CastFrom, CastInto, DInt, Float, FpResult, HInt, Int, IntTy, MinInt, Round, Status,
};
/// Fused multiply-add that works when there is not a larger float size available. Computes
/// `(x * y) + z`.
#[inline]
pub fn fma_round<F>(x: F, y: F, z: F, _round: Round) -> FpResult<F>
where
F: Float,
F: CastFrom<F::SignedInt>,
F: CastFrom<i8>,
F::Int: HInt,
u32: CastInto<F::Int>,
{
let one = IntTy::<F>::ONE;
let zero = IntTy::<F>::ZERO;
// Normalize such that the top of the mantissa is zero and we have a guard bit.
let nx = Norm::from_float(x);
let ny = Norm::from_float(y);
let nz = Norm::from_float(z);
if nx.is_zero_nan_inf() || ny.is_zero_nan_inf() {
// Value will overflow, defer to non-fused operations.
return FpResult::ok(x * y + z);
}
if nz.is_zero_nan_inf() {
if nz.is_zero() {
// Empty add component means we only need to multiply.
return FpResult::ok(x * y);
}
// `z` is NaN or infinity, which sets the result.
return FpResult::ok(z);
}
// multiply: r = x * y
let zhi: F::Int;
let zlo: F::Int;
let (mut rlo, mut rhi) = nx.m.widen_mul(ny.m).lo_hi();
// Exponent result of multiplication
let mut e: i32 = nx.e + ny.e;
// Needed shift to align `z` to the multiplication result
let mut d: i32 = nz.e - e;
let sbits = F::BITS as i32;
// Scale `z`. Shift `z <<= kz`, `r >>= kr`, so `kz+kr == d`, set `e = e+kr` (== ez-kz)
if d > 0 {
// The magnitude of `z` is larger than `x * y`
if d < sbits {
// Maximum shift of one `F::BITS` means shifted `z` will fit into `2 * F::BITS`. Shift
// it into `(zhi, zlo)`. No exponent adjustment necessary.
zlo = nz.m << d;
zhi = nz.m >> (sbits - d);
} else {
// Shift larger than `sbits`, `z` only needs the top half `zhi`. Place it there (acts
// as a shift by `sbits`).
zlo = zero;
zhi = nz.m;
d -= sbits;
// `z`'s exponent is large enough that it now needs to be taken into account.
e = nz.e - sbits;
if d == 0 {
// Exactly `sbits`, nothing to do
} else if d < sbits {
// Remaining shift fits within `sbits`. Leave `z` in place, shift `x * y`
rlo = (rhi << (sbits - d)) | (rlo >> d);
// Set the sticky bit
rlo |= IntTy::<F>::from((rlo << (sbits - d)) != zero);
rhi = rhi >> d;
} else {
// `z`'s magnitude is enough that `x * y` is irrelevant. It was nonzero, so set
// the sticky bit.
rlo = one;
rhi = zero;
}
}
} else {
// `z`'s magnitude once shifted fits entirely within `zlo`
zhi = zero;
d = -d;
if d == 0 {
// No shift needed
zlo = nz.m;
} else if d < sbits {
// Shift s.t. `nz.m` fits into `zlo`
let sticky = IntTy::<F>::from((nz.m << (sbits - d)) != zero);
zlo = (nz.m >> d) | sticky;
} else {
// Would be entirely shifted out, only set the sticky bit
zlo = one;
}
}
/* addition */
let mut neg = nx.neg ^ ny.neg;
let samesign: bool = !neg ^ nz.neg;
let mut rhi_nonzero = true;
if samesign {
// r += z
rlo = rlo.wrapping_add(zlo);
rhi += zhi + IntTy::<F>::from(rlo < zlo);
} else {
// r -= z
let (res, borrow) = rlo.overflowing_sub(zlo);
rlo = res;
rhi = rhi.wrapping_sub(zhi.wrapping_add(IntTy::<F>::from(borrow)));
if (rhi >> (F::BITS - 1)) != zero {
rlo = rlo.signed().wrapping_neg().unsigned();
rhi = rhi.signed().wrapping_neg().unsigned() - IntTy::<F>::from(rlo != zero);
neg = !neg;
}
rhi_nonzero = rhi != zero;
}
/* Construct result */
// Shift result into `rhi`, left-aligned. Last bit is sticky
if rhi_nonzero {
// `d` > 0, need to shift both `rhi` and `rlo` into result
e += sbits;
d = rhi.leading_zeros() as i32 - 1;
rhi = (rhi << d) | (rlo >> (sbits - d));
// Update sticky
rhi |= IntTy::<F>::from((rlo << d) != zero);
} else if rlo != zero {
// `rhi` is zero, `rlo` is the entire result and needs to be shifted
d = rlo.leading_zeros() as i32 - 1;
if d < 0 {
// Shift and set sticky
rhi = (rlo >> 1) | (rlo & one);
} else {
rhi = rlo << d;
}
} else {
// exact +/- 0.0
return FpResult::ok(x * y + z);
}
e -= d;
// Use int->float conversion to populate the significand.
// i is in [1 << (BITS - 2), (1 << (BITS - 1)) - 1]
let mut i: F::SignedInt = rhi.signed();
if neg {
i = -i;
}
// `|r|` is in `[0x1p62,0x1p63]` for `f64`
let mut r: F = F::cast_from_lossy(i);
/* Account for subnormal and rounding */
// Unbiased exponent for the maximum value of `r`
let max_pow = F::BITS - 1 + F::EXP_BIAS;
let mut status = Status::OK;
if e < -(max_pow as i32 - 2) {
// Result is subnormal before rounding
if e == -(max_pow as i32 - 1) {
let mut c = F::from_parts(false, max_pow, zero);
if neg {
c = -c;
}
if r == c {
// Min normal after rounding,
status.set_underflow(true);
r = F::MIN_POSITIVE_NORMAL.copysign(r);
return FpResult::new(r, status);
}
if (rhi << (F::SIG_BITS + 1)) != zero {
// Account for truncated bits. One bit will be lost in the `scalbn` call, add
// another top bit to avoid double rounding if inexact.
let iu: F::Int = (rhi >> 1) | (rhi & one) | (one << (F::BITS - 2));
i = iu.signed();
if neg {
i = -i;
}
r = F::cast_from_lossy(i);
// Remove the top bit
r = F::cast_from(2i8) * r - c;
status.set_underflow(true);
}
} else {
// Only round once when scaled
d = F::EXP_BITS as i32 - 1;
let sticky = IntTy::<F>::from(rhi << (F::BITS as i32 - d) != zero);
i = (((rhi >> d) | sticky) << d).signed();
if neg {
i = -i;
}
r = F::cast_from_lossy(i);
}
}
// Use our exponent to scale the final value.
FpResult::new(super::scalbn(r, e), status)
}
/// Representation of `F` that has handled subnormals.
#[derive(Clone, Copy, Debug)]
struct Norm<F: Float> {
/// Normalized significand with one guard bit, unsigned.
m: F::Int,
/// Exponent of the mantissa such that `m * 2^e = x`. Accounts for the shift in the mantissa
/// and the guard bit; that is, 1.0 will normalize as `m = 1 << 53` and `e = -53`.
e: i32,
neg: bool,
}
impl<F: Float> Norm<F> {
/// Unbias the exponent and account for the mantissa's precision, including the guard bit.
const EXP_UNBIAS: u32 = F::EXP_BIAS + F::SIG_BITS + 1;
/// Values greater than this had a saturated exponent (infinity or NaN), OR were zero and we
/// adjusted the exponent such that it exceeds this threashold.
const ZERO_INF_NAN: u32 = F::EXP_SAT - Self::EXP_UNBIAS;
fn from_float(x: F) -> Self {
let mut ix = x.to_bits();
let mut e = x.ex() as i32;
let neg = x.is_sign_negative();
if e == 0 {
// Normalize subnormals by multiplication
let scale_i = F::BITS - 1;
let scale_f = F::from_parts(false, scale_i + F::EXP_BIAS, F::Int::ZERO);
let scaled = x * scale_f;
ix = scaled.to_bits();
e = scaled.ex() as i32;
e = if e == 0 {
// If the exponent is still zero, the input was zero. Artifically set this value
// such that the final `e` will exceed `ZERO_INF_NAN`.
1 << F::EXP_BITS
} else {
// Otherwise, account for the scaling we just did.
e - scale_i as i32
};
}
e -= Self::EXP_UNBIAS as i32;
// Absolute value, set the implicit bit, and shift to create a guard bit
ix &= F::SIG_MASK;
ix |= F::IMPLICIT_BIT;
ix <<= 1;
Self { m: ix, e, neg }
}
/// True if the value was zero, infinity, or NaN.
fn is_zero_nan_inf(self) -> bool {
self.e >= Self::ZERO_INF_NAN as i32
}
/// The only value we have
fn is_zero(self) -> bool {
// The only exponent that strictly exceeds this value is our sentinel value for zero.
self.e > Self::ZERO_INF_NAN as i32
}
}

View File

@@ -0,0 +1,73 @@
use crate::support::{
CastFrom, CastInto, DFloat, Float, FpResult, HFloat, IntTy, MinInt, Round, Status,
};
/// Fma implementation when a hardware-backed larger float type is available. For `f32` and `f64`,
/// `f64` has enough precision to represent the `f32` in its entirety, except for double rounding.
#[inline]
pub fn fma_wide_round<F, B>(x: F, y: F, z: F, round: Round) -> FpResult<F>
where
F: Float + HFloat<D = B>,
B: Float + DFloat<H = F>,
B::Int: CastInto<i32>,
i32: CastFrom<i32>,
{
let one = IntTy::<B>::ONE;
let xy: B = x.widen() * y.widen();
let mut result: B = xy + z.widen();
let mut ui: B::Int = result.to_bits();
let re = result.ex();
let zb: B = z.widen();
let prec_diff = B::SIG_BITS - F::SIG_BITS;
let excess_prec = ui & ((one << prec_diff) - one);
let halfway = one << (prec_diff - 1);
// Common case: the larger precision is fine if...
// This is not a halfway case
if excess_prec != halfway
// Or the result is NaN
|| re == B::EXP_SAT
// Or the result is exact
|| (result - xy == zb && result - zb == xy)
// Or the mode is something other than round to nearest
|| round != Round::Nearest
{
let min_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN_SUBNORM) as u32;
let max_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN) as u32;
let mut status = Status::OK;
if (min_inexact_exp..max_inexact_exp).contains(&re) && status.inexact() {
// This branch is never hit; requires previous operations to set a status
status.set_inexact(false);
result = xy + z.widen();
if status.inexact() {
status.set_underflow(true);
} else {
status.set_inexact(true);
}
}
return FpResult {
val: result.narrow(),
status,
};
}
let neg = ui >> (B::BITS - 1) != IntTy::<B>::ZERO;
let err = if neg == (zb > xy) {
xy - result + zb
} else {
zb - result + xy
};
if neg == (err < B::ZERO) {
ui += one;
} else {
ui -= one;
}
FpResult::ok(B::from_bits(ui).narrow())
}

24
vendor/libm/src/math/generic/fmax.rs vendored Normal file
View File

@@ -0,0 +1,24 @@
/* SPDX-License-Identifier: MIT OR Apache-2.0 */
//! IEEE 754-2011 `maxNum`. This has been superseded by IEEE 754-2019 `maximumNumber`.
//!
//! Per the spec, returns the canonicalized result of:
//! - `x` if `x > y`
//! - `y` if `y > x`
//! - The other number if one is NaN
//! - Otherwise, either `x` or `y`, canonicalized
//! - -0.0 and +0.0 may be disregarded (unlike newer operations)
//!
//! Excluded from our implementation is sNaN handling.
//!
//! More on the differences: [link].
//!
//! [link]: https://grouper.ieee.org/groups/msc/ANSI_IEEE-Std-754-2019/background/minNum_maxNum_Removal_Demotion_v3.pdf
use crate::support::Float;
#[inline]
pub fn fmax<F: Float>(x: F, y: F) -> F {
let res = if x.is_nan() || x < y { y } else { x };
// Canonicalize
res * F::ONE
}

View File

@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: MIT OR Apache-2.0 */
//! IEEE 754-2019 `maximum`.
//!
//! Per the spec, returns the canonicalized result of:
//! - `x` if `x > y`
//! - `y` if `y > x`
//! - qNaN if either operation is NaN
//! - Logic following +0.0 > -0.0
//!
//! Excluded from our implementation is sNaN handling.
use crate::support::Float;
#[inline]
pub fn fmaximum<F: Float>(x: F, y: F) -> F {
let res = if x.is_nan() {
x
} else if y.is_nan() {
y
} else if x > y || (y.to_bits() == F::NEG_ZERO.to_bits() && x.is_sign_positive()) {
x
} else {
y
};
// Canonicalize
res * F::ONE
}

View File

@@ -0,0 +1,27 @@
/* SPDX-License-Identifier: MIT OR Apache-2.0 */
//! IEEE 754-2019 `maximumNumber`.
//!
//! Per the spec, returns:
//! - `x` if `x > y`
//! - `y` if `y > x`
//! - Non-NaN if one operand is NaN
//! - Logic following +0.0 > -0.0
//! - Either `x` or `y` if `x == y` and the signs are the same
//! - qNaN if either operand is a NaN
//!
//! Excluded from our implementation is sNaN handling.
use crate::support::Float;
#[inline]
pub fn fmaximum_num<F: Float>(x: F, y: F) -> F {
let res =
if x.is_nan() || x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) {
y
} else {
x
};
// Canonicalize
res * F::ONE
}

24
vendor/libm/src/math/generic/fmin.rs vendored Normal file
View File

@@ -0,0 +1,24 @@
/* SPDX-License-Identifier: MIT OR Apache-2.0 */
//! IEEE 754-2008 `minNum`. This has been superseded by IEEE 754-2019 `minimumNumber`.
//!
//! Per the spec, returns the canonicalized result of:
//! - `x` if `x < y`
//! - `y` if `y < x`
//! - The other number if one is NaN
//! - Otherwise, either `x` or `y`, canonicalized
//! - -0.0 and +0.0 may be disregarded (unlike newer operations)
//!
//! Excluded from our implementation is sNaN handling.
//!
//! More on the differences: [link].
//!
//! [link]: https://grouper.ieee.org/groups/msc/ANSI_IEEE-Std-754-2019/background/minNum_maxNum_Removal_Demotion_v3.pdf
use crate::support::Float;
#[inline]
pub fn fmin<F: Float>(x: F, y: F) -> F {
let res = if y.is_nan() || x < y { x } else { y };
// Canonicalize
res * F::ONE
}

View File

@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: MIT OR Apache-2.0 */
//! IEEE 754-2019 `minimum`.
//!
//! Per the spec, returns the canonicalized result of:
//! - `x` if `x < y`
//! - `y` if `y < x`
//! - qNaN if either operation is NaN
//! - Logic following +0.0 > -0.0
//!
//! Excluded from our implementation is sNaN handling.
use crate::support::Float;
#[inline]
pub fn fminimum<F: Float>(x: F, y: F) -> F {
let res = if x.is_nan() {
x
} else if y.is_nan() {
y
} else if x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) {
x
} else {
y
};
// Canonicalize
res * F::ONE
}

View File

@@ -0,0 +1,27 @@
/* SPDX-License-Identifier: MIT OR Apache-2.0 */
//! IEEE 754-2019 `minimum`.
//!
//! Per the spec, returns:
//! - `x` if `x < y`
//! - `y` if `y < x`
//! - Non-NaN if one operand is NaN
//! - Logic following +0.0 > -0.0
//! - Either `x` or `y` if `x == y` and the signs are the same
//! - qNaN if either operand is a NaN
//!
//! Excluded from our implementation is sNaN handling.
use crate::support::Float;
#[inline]
pub fn fminimum_num<F: Float>(x: F, y: F) -> F {
let res =
if y.is_nan() || x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) {
x
} else {
y
};
// Canonicalize
res * F::ONE
}

68
vendor/libm/src/math/generic/fmod.rs vendored Normal file
View File

@@ -0,0 +1,68 @@
/* SPDX-License-Identifier: MIT OR Apache-2.0 */
use crate::support::{CastFrom, Float, Int, MinInt};
#[inline]
pub fn fmod<F: Float>(x: F, y: F) -> F {
let _1 = F::Int::ONE;
let sx = x.to_bits() & F::SIGN_MASK;
let ux = x.to_bits() & !F::SIGN_MASK;
let uy = y.to_bits() & !F::SIGN_MASK;
// Cases that return NaN:
// NaN % _
// Inf % _
// _ % NaN
// _ % 0
let x_nan_or_inf = ux & F::EXP_MASK == F::EXP_MASK;
let y_nan_or_zero = uy.wrapping_sub(_1) & F::EXP_MASK == F::EXP_MASK;
if x_nan_or_inf | y_nan_or_zero {
return (x * y) / (x * y);
}
if ux < uy {
// |x| < |y|
return x;
}
let (num, ex) = into_sig_exp::<F>(ux);
let (div, ey) = into_sig_exp::<F>(uy);
// To compute `(num << ex) % (div << ey)`, first
// evaluate `rem = (num << (ex - ey)) % div` ...
let rem = reduction(num, ex - ey, div);
// ... so the result will be `rem << ey`
if rem.is_zero() {
// Return zero with the sign of `x`
return F::from_bits(sx);
};
// We would shift `rem` up by `ey`, but have to stop at `F::SIG_BITS`
let shift = ey.min(F::SIG_BITS - rem.ilog2());
// Anything past that is added to the exponent field
let bits = (rem << shift) + (F::Int::cast_from(ey - shift) << F::SIG_BITS);
F::from_bits(sx + bits)
}
/// Given the bits of a finite float, return a tuple of
/// - the mantissa with the implicit bit (0 if subnormal, 1 otherwise)
/// - the additional exponent past 1, (0 for subnormal, 0 or more otherwise)
fn into_sig_exp<F: Float>(mut bits: F::Int) -> (F::Int, u32) {
bits &= !F::SIGN_MASK;
// Subtract 1 from the exponent, clamping at 0
let sat = bits.checked_sub(F::IMPLICIT_BIT).unwrap_or(F::Int::ZERO);
(
bits - (sat & F::EXP_MASK),
u32::cast_from(sat >> F::SIG_BITS),
)
}
/// Compute the remainder `(x * 2.pow(e)) % y` without overflow.
fn reduction<I: Int>(mut x: I, e: u32, y: I) -> I {
x %= y;
for _ in 0..e {
x <<= 1;
x = x.checked_sub(y).unwrap_or(x);
}
x
}

42
vendor/libm/src/math/generic/mod.rs vendored Normal file
View File

@@ -0,0 +1,42 @@
// Note: generic functions are marked `#[inline]` because, even though generic functions are
// typically inlined, this does not seem to always be the case.
mod ceil;
mod copysign;
mod fabs;
mod fdim;
mod floor;
mod fma;
mod fma_wide;
mod fmax;
mod fmaximum;
mod fmaximum_num;
mod fmin;
mod fminimum;
mod fminimum_num;
mod fmod;
mod rint;
mod round;
mod scalbn;
mod sqrt;
mod trunc;
pub use ceil::ceil;
pub use copysign::copysign;
pub use fabs::fabs;
pub use fdim::fdim;
pub use floor::floor;
pub use fma::fma_round;
pub use fma_wide::fma_wide_round;
pub use fmax::fmax;
pub use fmaximum::fmaximum;
pub use fmaximum_num::fmaximum_num;
pub use fmin::fmin;
pub use fminimum::fminimum;
pub use fminimum_num::fminimum_num;
pub use fmod::fmod;
pub use rint::rint_round;
pub use round::round;
pub use scalbn::scalbn;
pub use sqrt::sqrt;
pub use trunc::trunc;

130
vendor/libm/src/math/generic/rint.rs vendored Normal file
View File

@@ -0,0 +1,130 @@
/* SPDX-License-Identifier: MIT */
/* origin: musl src/math/rint.c */
use crate::support::{Float, FpResult, Round};
/// IEEE 754-2019 `roundToIntegralExact`, which respects rounding mode and raises inexact if
/// applicable.
#[inline]
pub fn rint_round<F: Float>(x: F, _round: Round) -> FpResult<F> {
let toint = F::ONE / F::EPSILON;
let e = x.ex();
let positive = x.is_sign_positive();
// On i386 `force_eval!` must be used to force rounding via storage to memory. Otherwise,
// the excess precission from x87 would cause an incorrect final result.
let force = |x| {
if cfg!(x86_no_sse) && (F::BITS == 32 || F::BITS == 64) {
force_eval!(x)
} else {
x
}
};
let res = if e >= F::EXP_BIAS + F::SIG_BITS {
// No fractional part; exact result can be returned.
x
} else {
// Apply a net-zero adjustment that nudges `y` in the direction of the rounding mode. For
// Rust this is always nearest, but ideally it would take `round` into account.
let y = if positive {
force(force(x) + toint) - toint
} else {
force(force(x) - toint) + toint
};
if y == F::ZERO {
// A zero result takes the sign of the input.
if positive { F::ZERO } else { F::NEG_ZERO }
} else {
y
}
};
FpResult::ok(res)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::support::{Hexf, Status};
fn spec_test<F: Float>(cases: &[(F, F, Status)]) {
let roundtrip = [
F::ZERO,
F::ONE,
F::NEG_ONE,
F::NEG_ZERO,
F::INFINITY,
F::NEG_INFINITY,
];
for x in roundtrip {
let FpResult { val, status } = rint_round(x, Round::Nearest);
assert_biteq!(val, x, "rint_round({})", Hexf(x));
assert_eq!(status, Status::OK, "{}", Hexf(x));
}
for &(x, res, res_stat) in cases {
let FpResult { val, status } = rint_round(x, Round::Nearest);
assert_biteq!(val, res, "rint_round({})", Hexf(x));
assert_eq!(status, res_stat, "{}", Hexf(x));
}
}
#[test]
#[cfg(f16_enabled)]
fn spec_tests_f16() {
let cases = [];
spec_test::<f16>(&cases);
}
#[test]
fn spec_tests_f32() {
let cases = [
(0.1, 0.0, Status::OK),
(-0.1, -0.0, Status::OK),
(0.5, 0.0, Status::OK),
(-0.5, -0.0, Status::OK),
(0.9, 1.0, Status::OK),
(-0.9, -1.0, Status::OK),
(1.1, 1.0, Status::OK),
(-1.1, -1.0, Status::OK),
(1.5, 2.0, Status::OK),
(-1.5, -2.0, Status::OK),
(1.9, 2.0, Status::OK),
(-1.9, -2.0, Status::OK),
(2.8, 3.0, Status::OK),
(-2.8, -3.0, Status::OK),
];
spec_test::<f32>(&cases);
}
#[test]
fn spec_tests_f64() {
let cases = [
(0.1, 0.0, Status::OK),
(-0.1, -0.0, Status::OK),
(0.5, 0.0, Status::OK),
(-0.5, -0.0, Status::OK),
(0.9, 1.0, Status::OK),
(-0.9, -1.0, Status::OK),
(1.1, 1.0, Status::OK),
(-1.1, -1.0, Status::OK),
(1.5, 2.0, Status::OK),
(-1.5, -2.0, Status::OK),
(1.9, 2.0, Status::OK),
(-1.9, -2.0, Status::OK),
(2.8, 3.0, Status::OK),
(-2.8, -3.0, Status::OK),
];
spec_test::<f64>(&cases);
}
#[test]
#[cfg(f128_enabled)]
fn spec_tests_f128() {
let cases = [];
spec_test::<f128>(&cases);
}
}

83
vendor/libm/src/math/generic/round.rs vendored Normal file
View File

@@ -0,0 +1,83 @@
use super::{copysign, trunc};
use crate::support::{Float, MinInt};
#[inline]
pub fn round<F: Float>(x: F) -> F {
let f0p5 = F::from_parts(false, F::EXP_BIAS - 1, F::Int::ZERO); // 0.5
let f0p25 = F::from_parts(false, F::EXP_BIAS - 2, F::Int::ZERO); // 0.25
trunc(x + copysign(f0p5 - f0p25 * F::EPSILON, x))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[cfg(f16_enabled)]
fn zeroes_f16() {
assert_biteq!(round(0.0_f16), 0.0_f16);
assert_biteq!(round(-0.0_f16), -0.0_f16);
}
#[test]
#[cfg(f16_enabled)]
fn sanity_check_f16() {
assert_eq!(round(-1.0_f16), -1.0);
assert_eq!(round(2.8_f16), 3.0);
assert_eq!(round(-0.5_f16), -1.0);
assert_eq!(round(0.5_f16), 1.0);
assert_eq!(round(-1.5_f16), -2.0);
assert_eq!(round(1.5_f16), 2.0);
}
#[test]
fn zeroes_f32() {
assert_biteq!(round(0.0_f32), 0.0_f32);
assert_biteq!(round(-0.0_f32), -0.0_f32);
}
#[test]
fn sanity_check_f32() {
assert_eq!(round(-1.0_f32), -1.0);
assert_eq!(round(2.8_f32), 3.0);
assert_eq!(round(-0.5_f32), -1.0);
assert_eq!(round(0.5_f32), 1.0);
assert_eq!(round(-1.5_f32), -2.0);
assert_eq!(round(1.5_f32), 2.0);
}
#[test]
fn zeroes_f64() {
assert_biteq!(round(0.0_f64), 0.0_f64);
assert_biteq!(round(-0.0_f64), -0.0_f64);
}
#[test]
fn sanity_check_f64() {
assert_eq!(round(-1.0_f64), -1.0);
assert_eq!(round(2.8_f64), 3.0);
assert_eq!(round(-0.5_f64), -1.0);
assert_eq!(round(0.5_f64), 1.0);
assert_eq!(round(-1.5_f64), -2.0);
assert_eq!(round(1.5_f64), 2.0);
}
#[test]
#[cfg(f128_enabled)]
fn zeroes_f128() {
assert_biteq!(round(0.0_f128), 0.0_f128);
assert_biteq!(round(-0.0_f128), -0.0_f128);
}
#[test]
#[cfg(f128_enabled)]
fn sanity_check_f128() {
assert_eq!(round(-1.0_f128), -1.0);
assert_eq!(round(2.8_f128), 3.0);
assert_eq!(round(-0.5_f128), -1.0);
assert_eq!(round(0.5_f128), 1.0);
assert_eq!(round(-1.5_f128), -2.0);
assert_eq!(round(1.5_f128), 2.0);
}
}

121
vendor/libm/src/math/generic/scalbn.rs vendored Normal file
View File

@@ -0,0 +1,121 @@
use crate::support::{CastFrom, CastInto, Float, IntTy, MinInt};
/// Scale the exponent.
///
/// From N3220:
///
/// > The scalbn and scalbln functions compute `x * b^n`, where `b = FLT_RADIX` if the return type
/// > of the function is a standard floating type, or `b = 10` if the return type of the function
/// > is a decimal floating type. A range error occurs for some finite x, depending on n.
/// >
/// > [...]
/// >
/// > * `scalbn(±0, n)` returns `±0`.
/// > * `scalbn(x, 0)` returns `x`.
/// > * `scalbn(±∞, n)` returns `±∞`.
/// >
/// > If the calculation does not overflow or underflow, the returned value is exact and
/// > independent of the current rounding direction mode.
#[inline]
pub fn scalbn<F: Float>(mut x: F, mut n: i32) -> F
where
u32: CastInto<F::Int>,
F::Int: CastFrom<i32>,
F::Int: CastFrom<u32>,
{
let zero = IntTy::<F>::ZERO;
// Bits including the implicit bit
let sig_total_bits = F::SIG_BITS + 1;
// Maximum and minimum values when biased
let exp_max = F::EXP_MAX;
let exp_min = F::EXP_MIN;
// 2 ^ Emax, maximum positive with null significand (0x1p1023 for f64)
let f_exp_max = F::from_parts(false, F::EXP_BIAS << 1, zero);
// 2 ^ Emin, minimum positive normal with null significand (0x1p-1022 for f64)
let f_exp_min = F::from_parts(false, 1, zero);
// 2 ^ sig_total_bits, moltiplier to normalize subnormals (0x1p53 for f64)
let f_pow_subnorm = F::from_parts(false, sig_total_bits + F::EXP_BIAS, zero);
/*
* The goal is to multiply `x` by a scale factor that applies `n`. However, there are cases
* where `2^n` is not representable by `F` but the result should be, e.g. `x = 2^Emin` with
* `n = -EMin + 2` (one out of range of 2^Emax). To get around this, reduce the magnitude of
* the final scale operation by prescaling by the max/min power representable by `F`.
*/
if n > exp_max {
// Worse case positive `n`: `x` is the minimum subnormal value, the result is `F::MAX`.
// This can be reached by three scaling multiplications (two here and one final).
debug_assert!(-exp_min + F::SIG_BITS as i32 + exp_max <= exp_max * 3);
x *= f_exp_max;
n -= exp_max;
if n > exp_max {
x *= f_exp_max;
n -= exp_max;
if n > exp_max {
n = exp_max;
}
}
} else if n < exp_min {
// When scaling toward 0, the prescaling is limited to a value that does not allow `x` to
// go subnormal. This avoids double rounding.
if F::BITS > 16 {
// `mul` s.t. `!(x * mul).is_subnormal() ∀ x`
let mul = f_exp_min * f_pow_subnorm;
let add = -exp_min - sig_total_bits as i32;
// Worse case negative `n`: `x` is the maximum positive value, the result is `F::MIN`.
// This must be reachable by three scaling multiplications (two here and one final).
debug_assert!(-exp_min + F::SIG_BITS as i32 + exp_max <= add * 2 + -exp_min);
x *= mul;
n += add;
if n < exp_min {
x *= mul;
n += add;
if n < exp_min {
n = exp_min;
}
}
} else {
// `f16` is unique compared to other float types in that the difference between the
// minimum exponent and the significand bits (`add = -exp_min - sig_total_bits`) is
// small, only three. The above method depend on decrementing `n` by `add` two times;
// for other float types this works out because `add` is a substantial fraction of
// the exponent range. For `f16`, however, 3 is relatively small compared to the
// exponent range (which is 39), so that requires ~10 prescale rounds rather than two.
//
// Work aroudn this by using a different algorithm that calculates the prescale
// dynamically based on the maximum possible value. This adds more operations per round
// since it needs to construct the scale, but works better in the general case.
let add = -(n + sig_total_bits as i32).clamp(exp_min, sig_total_bits as i32);
let mul = F::from_parts(false, (F::EXP_BIAS as i32 - add) as u32, zero);
x *= mul;
n += add;
if n < exp_min {
let add = -(n + sig_total_bits as i32).clamp(exp_min, sig_total_bits as i32);
let mul = F::from_parts(false, (F::EXP_BIAS as i32 - add) as u32, zero);
x *= mul;
n += add;
if n < exp_min {
n = exp_min;
}
}
}
}
let scale = F::from_parts(false, (F::EXP_BIAS as i32 + n) as u32, zero);
x * scale
}

541
vendor/libm/src/math/generic/sqrt.rs vendored Normal file
View File

@@ -0,0 +1,541 @@
/* SPDX-License-Identifier: MIT */
/* origin: musl src/math/sqrt.c. Ported to generic Rust algorithm in 2025, TG. */
//! Generic square root algorithm.
//!
//! This routine operates around `m_u2`, a U.2 (fixed point with two integral bits) mantissa
//! within the range [1, 4). A table lookup provides an initial estimate, then goldschmidt
//! iterations at various widths are used to approach the real values.
//!
//! For the iterations, `r` is a U0 number that approaches `1/sqrt(m_u2)`, and `s` is a U2 number
//! that approaches `sqrt(m_u2)`. Recall that m_u2 ∈ [1, 4).
//!
//! With Newton-Raphson iterations, this would be:
//!
//! - `w = r * r w ~ 1 / m`
//! - `u = 3 - m * w u ~ 3 - m * w = 3 - m / m = 2`
//! - `r = r * u / 2 r ~ r`
//!
//! (Note that the righthand column does not show anything analytically meaningful (i.e. r ~ r),
//! since the value of performing one iteration is in reducing the error representable by `~`).
//!
//! Instead of Newton-Raphson iterations, Goldschmidt iterations are used to calculate
//! `s = m * r`:
//!
//! - `s = m * r s ~ m / sqrt(m)`
//! - `u = 3 - s * r u ~ 3 - (m / sqrt(m)) * (1 / sqrt(m)) = 3 - m / m = 2`
//! - `r = r * u / 2 r ~ r`
//! - `s = s * u / 2 s ~ s`
//!
//! The above is precise because it uses the original value `m`. There is also a faster version
//! that performs fewer steps but does not use `m`:
//!
//! - `u = 3 - s * r u ~ 3 - 1`
//! - `r = r * u / 2 r ~ r`
//! - `s = s * u / 2 s ~ s`
//!
//! Rounding errors accumulate faster with the second version, so it is only used for subsequent
//! iterations within the same width integer. The first version is always used for the first
//! iteration at a new width in order to avoid this accumulation.
//!
//! Goldschmidt has the advantage over Newton-Raphson that `sqrt(x)` and `1/sqrt(x)` are
//! computed at the same time, i.e. there is no need to calculate `1/sqrt(x)` and invert it.
use crate::support::{
CastFrom, CastInto, DInt, Float, FpResult, HInt, Int, IntTy, MinInt, Round, Status, cold_path,
};
#[inline]
pub fn sqrt<F>(x: F) -> F
where
F: Float + SqrtHelper,
F::Int: HInt,
F::Int: From<u8>,
F::Int: From<F::ISet2>,
F::Int: CastInto<F::ISet1>,
F::Int: CastInto<F::ISet2>,
u32: CastInto<F::Int>,
{
sqrt_round(x, Round::Nearest).val
}
#[inline]
pub fn sqrt_round<F>(x: F, _round: Round) -> FpResult<F>
where
F: Float + SqrtHelper,
F::Int: HInt,
F::Int: From<u8>,
F::Int: From<F::ISet2>,
F::Int: CastInto<F::ISet1>,
F::Int: CastInto<F::ISet2>,
u32: CastInto<F::Int>,
{
let zero = IntTy::<F>::ZERO;
let one = IntTy::<F>::ONE;
let mut ix = x.to_bits();
// Top is the exponent and sign, which may or may not be shifted. If the float fits into a
// `u32`, we can get by without paying shifting costs.
let noshift = F::BITS <= u32::BITS;
let (mut top, special_case) = if noshift {
let exp_lsb = one << F::SIG_BITS;
let special_case = ix.wrapping_sub(exp_lsb) >= F::EXP_MASK - exp_lsb;
(Exp::NoShift(()), special_case)
} else {
let top = u32::cast_from(ix >> F::SIG_BITS);
let special_case = top.wrapping_sub(1) >= F::EXP_SAT - 1;
(Exp::Shifted(top), special_case)
};
// Handle NaN, zero, and out of domain (<= 0)
if special_case {
cold_path();
// +/-0
if ix << 1 == zero {
return FpResult::ok(x);
}
// Positive infinity
if ix == F::EXP_MASK {
return FpResult::ok(x);
}
// NaN or negative
if ix > F::EXP_MASK {
return FpResult::new(F::NAN, Status::INVALID);
}
// Normalize subnormals by multiplying by 1.0 << SIG_BITS (e.g. 0x1p52 for doubles).
let scaled = x * F::from_parts(false, F::SIG_BITS + F::EXP_BIAS, zero);
ix = scaled.to_bits();
match top {
Exp::Shifted(ref mut v) => {
*v = scaled.ex();
*v = (*v).wrapping_sub(F::SIG_BITS);
}
Exp::NoShift(()) => {
ix = ix.wrapping_sub((F::SIG_BITS << F::SIG_BITS).cast());
}
}
}
// Reduce arguments such that `x = 4^e * m`:
//
// - m_u2 ∈ [1, 4), a fixed point U2.BITS number
// - 2^e is the exponent part of the result
let (m_u2, exp) = match top {
Exp::Shifted(top) => {
// We now know `x` is positive, so `top` is just its (biased) exponent
let mut e = top;
// Construct a fixed point representation of the mantissa.
let mut m_u2 = (ix | F::IMPLICIT_BIT) << F::EXP_BITS;
let even = (e & 1) != 0;
if even {
m_u2 >>= 1;
}
e = (e.wrapping_add(F::EXP_SAT >> 1)) >> 1;
(m_u2, Exp::Shifted(e))
}
Exp::NoShift(()) => {
let even = ix & (one << F::SIG_BITS) != zero;
// Exponent part of the return value
let mut e_noshift = ix >> 1;
// ey &= (F::EXP_MASK << 2) >> 2; // clear the top exponent bit (result = 1.0)
e_noshift += (F::EXP_MASK ^ (F::SIGN_MASK >> 1)) >> 1;
e_noshift &= F::EXP_MASK;
let m1 = (ix << F::EXP_BITS) | F::SIGN_MASK;
let m0 = (ix << (F::EXP_BITS - 1)) & !F::SIGN_MASK;
let m_u2 = if even { m0 } else { m1 };
(m_u2, Exp::NoShift(e_noshift))
}
};
// Extract the top 6 bits of the significand with the lowest bit of the exponent.
let i = usize::cast_from(ix >> (F::SIG_BITS - 6)) & 0b1111111;
// Start with an initial guess for `r = 1 / sqrt(m)` from the table, and shift `m` as an
// initial value for `s = sqrt(m)`. See the module documentation for details.
let r1_u0: F::ISet1 = F::ISet1::cast_from(RSQRT_TAB[i]) << (F::ISet1::BITS - 16);
let s1_u2: F::ISet1 = ((m_u2) >> (F::BITS - F::ISet1::BITS)).cast();
// Perform iterations, if any, at quarter width (used for `f128`).
let (r1_u0, _s1_u2) = goldschmidt::<F, F::ISet1>(r1_u0, s1_u2, F::SET1_ROUNDS, false);
// Widen values and perform iterations at half width (used for `f64` and `f128`).
let r2_u0: F::ISet2 = F::ISet2::from(r1_u0) << (F::ISet2::BITS - F::ISet1::BITS);
let s2_u2: F::ISet2 = ((m_u2) >> (F::BITS - F::ISet2::BITS)).cast();
let (r2_u0, _s2_u2) = goldschmidt::<F, F::ISet2>(r2_u0, s2_u2, F::SET2_ROUNDS, false);
// Perform final iterations at full width (used for all float types).
let r_u0: F::Int = F::Int::from(r2_u0) << (F::BITS - F::ISet2::BITS);
let s_u2: F::Int = m_u2;
let (_r_u0, s_u2) = goldschmidt::<F, F::Int>(r_u0, s_u2, F::FINAL_ROUNDS, true);
// Shift back to mantissa position.
let mut m = s_u2 >> (F::EXP_BITS - 2);
// The musl source includes the following comment (with literals replaced):
//
// > s < sqrt(m) < s + 0x1.09p-SIG_BITS
// > compute nearest rounded result: the nearest result to SIG_BITS bits is either s or
// > s+0x1p-SIG_BITS, we can decide by comparing (2^SIG_BITS s + 0.5)^2 to 2^(2*SIG_BITS) m.
//
// Expanding this with , with `SIG_BITS = p` and adjusting based on the operations done to
// `d0` and `d1`:
//
// - `2^(2p)m ≟ ((2^p)m + 0.5)^2`
// - `2^(2p)m ≟ 2^(2p)m^2 + (2^p)m + 0.25`
// - `2^(2p)m - m^2 ≟ (2^(2p) - 1)m^2 + (2^p)m + 0.25`
// - `(1 - 2^(2p))m + m^2 ≟ (1 - 2^(2p))m^2 + (1 - 2^p)m + 0.25` (?)
//
// I do not follow how the rounding bit is extracted from this comparison with the below
// operations. In any case, the algorithm is well tested.
// The value needed to shift `m_u2` by to create `m*2^(2p)`. `2p = 2 * F::SIG_BITS`,
// `F::BITS - 2` accounts for the offset that `m_u2` already has.
let shift = 2 * F::SIG_BITS - (F::BITS - 2);
// `2^(2p)m - m^2`
let d0 = (m_u2 << shift).wrapping_sub(m.wrapping_mul(m));
// `m - 2^(2p)m + m^2`
let d1 = m.wrapping_sub(d0);
m += d1 >> (F::BITS - 1);
m &= F::SIG_MASK;
match exp {
Exp::Shifted(e) => m |= IntTy::<F>::cast_from(e) << F::SIG_BITS,
Exp::NoShift(e) => m |= e,
};
let mut y = F::from_bits(m);
// FIXME(f16): the fenv math does not work for `f16`
if F::BITS > 16 {
// Handle rounding and inexact. `(m + 1)^2 == 2^shift m` is exact; for all other cases, add
// a tiny value to cause fenv effects.
let d2 = d1.wrapping_add(m).wrapping_add(one);
let mut tiny = if d2 == zero {
cold_path();
zero
} else {
F::IMPLICIT_BIT
};
tiny |= (d1 ^ d2) & F::SIGN_MASK;
let t = F::from_bits(tiny);
y = y + t;
}
FpResult::ok(y)
}
/// Multiply at the wider integer size, returning the high half.
fn wmulh<I: HInt>(a: I, b: I) -> I {
a.widen_mul(b).hi()
}
/// Perform `count` goldschmidt iterations, returning `(r_u0, s_u?)`.
///
/// - `r_u0` is the reciprocal `r ~ 1 / sqrt(m)`, as U0.
/// - `s_u2` is the square root, `s ~ sqrt(m)`, as U2.
/// - `count` is the number of iterations to perform.
/// - `final_set` should be true if this is the last round (same-sized integer). If so, the
/// returned `s` will be U3, for later shifting. Otherwise, the returned `s` is U2.
///
/// Note that performance relies on the optimizer being able to unroll these loops (reasonably
/// trivial, `count` is a constant when called).
#[inline]
fn goldschmidt<F, I>(mut r_u0: I, mut s_u2: I, count: u32, final_set: bool) -> (I, I)
where
F: SqrtHelper,
I: HInt + From<u8>,
{
let three_u2 = I::from(0b11u8) << (I::BITS - 2);
let mut u_u0 = r_u0;
for i in 0..count {
// First iteration: `s = m*r` (`u_u0 = r_u0` set above)
// Subsequent iterations: `s=s*u/2`
s_u2 = wmulh(s_u2, u_u0);
// Perform `s /= 2` if:
//
// 1. This is not the first iteration (the first iteration is `s = m*r`)...
// 2. ... and this is not the last set of iterations
// 3. ... or, if this is the last set, it is not the last iteration
//
// This step is not performed for the final iteration because the shift is combined with
// a later shift (moving `s` into the mantissa).
if i > 0 && (!final_set || i + 1 < count) {
s_u2 <<= 1;
}
// u = 3 - s*r
let d_u2 = wmulh(s_u2, r_u0);
u_u0 = three_u2.wrapping_sub(d_u2);
// r = r*u/2
r_u0 = wmulh(r_u0, u_u0) << 1;
}
(r_u0, s_u2)
}
/// Representation of whether we shift the exponent into a `u32`, or modify it in place to save
/// the shift operations.
enum Exp<T> {
/// The exponent has been shifted to a `u32` and is LSB-aligned.
Shifted(u32),
/// The exponent is in its natural position in integer repr.
NoShift(T),
}
/// Size-specific constants related to the square root routine.
pub trait SqrtHelper: Float {
/// Integer for the first set of rounds. If unused, set to the same type as the next set.
type ISet1: HInt + Into<Self::ISet2> + CastFrom<Self::Int> + From<u8>;
/// Integer for the second set of rounds. If unused, set to the same type as the next set.
type ISet2: HInt + From<Self::ISet1> + From<u8>;
/// Number of rounds at `ISet1`.
const SET1_ROUNDS: u32 = 0;
/// Number of rounds at `ISet2`.
const SET2_ROUNDS: u32 = 0;
/// Number of rounds at `Self::Int`.
const FINAL_ROUNDS: u32;
}
#[cfg(f16_enabled)]
impl SqrtHelper for f16 {
type ISet1 = u16; // unused
type ISet2 = u16; // unused
const FINAL_ROUNDS: u32 = 2;
}
impl SqrtHelper for f32 {
type ISet1 = u32; // unused
type ISet2 = u32; // unused
const FINAL_ROUNDS: u32 = 3;
}
impl SqrtHelper for f64 {
type ISet1 = u32; // unused
type ISet2 = u32;
const SET2_ROUNDS: u32 = 2;
const FINAL_ROUNDS: u32 = 2;
}
#[cfg(f128_enabled)]
impl SqrtHelper for f128 {
type ISet1 = u32;
type ISet2 = u64;
const SET1_ROUNDS: u32 = 1;
const SET2_ROUNDS: u32 = 2;
const FINAL_ROUNDS: u32 = 2;
}
/// A U0.16 representation of `1/sqrt(x)`.
///
/// The index is a 7-bit number consisting of a single exponent bit and 6 bits of significand.
#[rustfmt::skip]
static RSQRT_TAB: [u16; 128] = [
0xb451, 0xb2f0, 0xb196, 0xb044, 0xaef9, 0xadb6, 0xac79, 0xab43,
0xaa14, 0xa8eb, 0xa7c8, 0xa6aa, 0xa592, 0xa480, 0xa373, 0xa26b,
0xa168, 0xa06a, 0x9f70, 0x9e7b, 0x9d8a, 0x9c9d, 0x9bb5, 0x9ad1,
0x99f0, 0x9913, 0x983a, 0x9765, 0x9693, 0x95c4, 0x94f8, 0x9430,
0x936b, 0x92a9, 0x91ea, 0x912e, 0x9075, 0x8fbe, 0x8f0a, 0x8e59,
0x8daa, 0x8cfe, 0x8c54, 0x8bac, 0x8b07, 0x8a64, 0x89c4, 0x8925,
0x8889, 0x87ee, 0x8756, 0x86c0, 0x862b, 0x8599, 0x8508, 0x8479,
0x83ec, 0x8361, 0x82d8, 0x8250, 0x81c9, 0x8145, 0x80c2, 0x8040,
0xff02, 0xfd0e, 0xfb25, 0xf947, 0xf773, 0xf5aa, 0xf3ea, 0xf234,
0xf087, 0xeee3, 0xed47, 0xebb3, 0xea27, 0xe8a3, 0xe727, 0xe5b2,
0xe443, 0xe2dc, 0xe17a, 0xe020, 0xdecb, 0xdd7d, 0xdc34, 0xdaf1,
0xd9b3, 0xd87b, 0xd748, 0xd61a, 0xd4f1, 0xd3cd, 0xd2ad, 0xd192,
0xd07b, 0xcf69, 0xce5b, 0xcd51, 0xcc4a, 0xcb48, 0xca4a, 0xc94f,
0xc858, 0xc764, 0xc674, 0xc587, 0xc49d, 0xc3b7, 0xc2d4, 0xc1f4,
0xc116, 0xc03c, 0xbf65, 0xbe90, 0xbdbe, 0xbcef, 0xbc23, 0xbb59,
0xba91, 0xb9cc, 0xb90a, 0xb84a, 0xb78c, 0xb6d0, 0xb617, 0xb560,
];
#[cfg(test)]
mod tests {
use super::*;
/// Test behavior specified in IEEE 754 `squareRoot`.
fn spec_test<F>()
where
F: Float + SqrtHelper,
F::Int: HInt,
F::Int: From<u8>,
F::Int: From<F::ISet2>,
F::Int: CastInto<F::ISet1>,
F::Int: CastInto<F::ISet2>,
u32: CastInto<F::Int>,
{
// Values that should return a NaN and raise invalid
let nan = [F::NEG_INFINITY, F::NEG_ONE, F::NAN, F::MIN];
// Values that return unaltered
let roundtrip = [F::ZERO, F::NEG_ZERO, F::INFINITY];
for x in nan {
let FpResult { val, status } = sqrt_round(x, Round::Nearest);
assert!(val.is_nan());
assert!(status == Status::INVALID);
}
for x in roundtrip {
let FpResult { val, status } = sqrt_round(x, Round::Nearest);
assert_biteq!(val, x);
assert!(status == Status::OK);
}
}
#[test]
#[cfg(f16_enabled)]
fn sanity_check_f16() {
assert_biteq!(sqrt(100.0f16), 10.0);
assert_biteq!(sqrt(4.0f16), 2.0);
}
#[test]
#[cfg(f16_enabled)]
fn spec_tests_f16() {
spec_test::<f16>();
}
#[test]
#[cfg(f16_enabled)]
#[allow(clippy::approx_constant)]
fn conformance_tests_f16() {
let cases = [
(f16::PI, 0x3f17_u16),
// 10_000.0, using a hex literal for MSRV hack (Rust < 1.67 checks literal widths as
// part of the AST, so the `cfg` is irrelevant here).
(f16::from_bits(0x70e2), 0x5640_u16),
(f16::from_bits(0x0000000f), 0x13bf_u16),
(f16::INFINITY, f16::INFINITY.to_bits()),
];
for (input, output) in cases {
assert_biteq!(
sqrt(input),
f16::from_bits(output),
"input: {input:?} ({:#018x})",
input.to_bits()
);
}
}
#[test]
fn sanity_check_f32() {
assert_biteq!(sqrt(100.0f32), 10.0);
assert_biteq!(sqrt(4.0f32), 2.0);
}
#[test]
fn spec_tests_f32() {
spec_test::<f32>();
}
#[test]
#[allow(clippy::approx_constant)]
fn conformance_tests_f32() {
let cases = [
(f32::PI, 0x3fe2dfc5_u32),
(10000.0f32, 0x42c80000_u32),
(f32::from_bits(0x0000000f), 0x1b2f456f_u32),
(f32::INFINITY, f32::INFINITY.to_bits()),
];
for (input, output) in cases {
assert_biteq!(
sqrt(input),
f32::from_bits(output),
"input: {input:?} ({:#018x})",
input.to_bits()
);
}
}
#[test]
fn sanity_check_f64() {
assert_biteq!(sqrt(100.0f64), 10.0);
assert_biteq!(sqrt(4.0f64), 2.0);
}
#[test]
fn spec_tests_f64() {
spec_test::<f64>();
}
#[test]
#[allow(clippy::approx_constant)]
fn conformance_tests_f64() {
let cases = [
(f64::PI, 0x3ffc5bf891b4ef6a_u64),
(10000.0, 0x4059000000000000_u64),
(f64::from_bits(0x0000000f), 0x1e7efbdeb14f4eda_u64),
(f64::INFINITY, f64::INFINITY.to_bits()),
];
for (input, output) in cases {
assert_biteq!(
sqrt(input),
f64::from_bits(output),
"input: {input:?} ({:#018x})",
input.to_bits()
);
}
}
#[test]
#[cfg(f128_enabled)]
fn sanity_check_f128() {
assert_biteq!(sqrt(100.0f128), 10.0);
assert_biteq!(sqrt(4.0f128), 2.0);
}
#[test]
#[cfg(f128_enabled)]
fn spec_tests_f128() {
spec_test::<f128>();
}
#[test]
#[cfg(f128_enabled)]
#[allow(clippy::approx_constant)]
fn conformance_tests_f128() {
let cases = [
(f128::PI, 0x3fffc5bf891b4ef6aa79c3b0520d5db9_u128),
// 10_000.0, see `f16` for reasoning.
(
f128::from_bits(0x400c3880000000000000000000000000),
0x40059000000000000000000000000000_u128,
),
(
f128::from_bits(0x0000000f),
0x1fc9efbdeb14f4ed9b17ae807907e1e9_u128,
),
(f128::INFINITY, f128::INFINITY.to_bits()),
];
for (input, output) in cases {
assert_biteq!(
sqrt(input),
f128::from_bits(output),
"input: {input:?} ({:#018x})",
input.to_bits()
);
}
}
}

148
vendor/libm/src/math/generic/trunc.rs vendored Normal file
View File

@@ -0,0 +1,148 @@
/* SPDX-License-Identifier: MIT
* origin: musl src/math/trunc.c */
use crate::support::{Float, FpResult, Int, IntTy, MinInt, Status};
#[inline]
pub fn trunc<F: Float>(x: F) -> F {
trunc_status(x).val
}
#[inline]
pub fn trunc_status<F: Float>(x: F) -> FpResult<F> {
let mut xi: F::Int = x.to_bits();
let e: i32 = x.exp_unbiased();
// C1: The represented value has no fractional part, so no truncation is needed
if e >= F::SIG_BITS as i32 {
return FpResult::ok(x);
}
let mask = if e < 0 {
// C2: If the exponent is negative, the result will be zero so we mask out everything
// except the sign.
F::SIGN_MASK
} else {
// C3: Otherwise, we mask out the last `e` bits of the significand.
!(F::SIG_MASK >> e.unsigned())
};
// C4: If the to-be-masked-out portion is already zero, we have an exact result
if (xi & !mask) == IntTy::<F>::ZERO {
return FpResult::ok(x);
}
// C5: Otherwise the result is inexact and we will truncate. Raise `FE_INEXACT`, mask the
// result, and return.
let status = if xi & F::SIG_MASK == F::Int::ZERO {
Status::OK
} else {
Status::INEXACT
};
xi &= mask;
FpResult::new(F::from_bits(xi), status)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::support::Hexf;
fn spec_test<F: Float>(cases: &[(F, F, Status)]) {
let roundtrip = [
F::ZERO,
F::ONE,
F::NEG_ONE,
F::NEG_ZERO,
F::INFINITY,
F::NEG_INFINITY,
];
for x in roundtrip {
let FpResult { val, status } = trunc_status(x);
assert_biteq!(val, x, "{}", Hexf(x));
assert_eq!(status, Status::OK, "{}", Hexf(x));
}
for &(x, res, res_stat) in cases {
let FpResult { val, status } = trunc_status(x);
assert_biteq!(val, res, "{}", Hexf(x));
assert_eq!(status, res_stat, "{}", Hexf(x));
}
}
/* Skipping f16 / f128 "sanity_check"s and spec cases due to rejected literal lexing at MSRV */
#[test]
#[cfg(f16_enabled)]
fn spec_tests_f16() {
let cases = [];
spec_test::<f16>(&cases);
}
#[test]
fn sanity_check_f32() {
assert_eq!(trunc(0.5f32), 0.0);
assert_eq!(trunc(1.1f32), 1.0);
assert_eq!(trunc(2.9f32), 2.0);
}
#[test]
fn spec_tests_f32() {
let cases = [
(0.1, 0.0, Status::INEXACT),
(-0.1, -0.0, Status::INEXACT),
(0.9, 0.0, Status::INEXACT),
(-0.9, -0.0, Status::INEXACT),
(1.1, 1.0, Status::INEXACT),
(-1.1, -1.0, Status::INEXACT),
(1.9, 1.0, Status::INEXACT),
(-1.9, -1.0, Status::INEXACT),
];
spec_test::<f32>(&cases);
assert_biteq!(trunc(1.1f32), 1.0);
assert_biteq!(trunc(1.1f64), 1.0);
// C1
assert_biteq!(trunc(hf32!("0x1p23")), hf32!("0x1p23"));
assert_biteq!(trunc(hf64!("0x1p52")), hf64!("0x1p52"));
assert_biteq!(trunc(hf32!("-0x1p23")), hf32!("-0x1p23"));
assert_biteq!(trunc(hf64!("-0x1p52")), hf64!("-0x1p52"));
// C2
assert_biteq!(trunc(hf32!("0x1p-1")), 0.0);
assert_biteq!(trunc(hf64!("0x1p-1")), 0.0);
assert_biteq!(trunc(hf32!("-0x1p-1")), -0.0);
assert_biteq!(trunc(hf64!("-0x1p-1")), -0.0);
}
#[test]
fn sanity_check_f64() {
assert_eq!(trunc(1.1f64), 1.0);
assert_eq!(trunc(2.9f64), 2.0);
}
#[test]
fn spec_tests_f64() {
let cases = [
(0.1, 0.0, Status::INEXACT),
(-0.1, -0.0, Status::INEXACT),
(0.9, 0.0, Status::INEXACT),
(-0.9, -0.0, Status::INEXACT),
(1.1, 1.0, Status::INEXACT),
(-1.1, -1.0, Status::INEXACT),
(1.9, 1.0, Status::INEXACT),
(-1.9, -1.0, Status::INEXACT),
];
spec_test::<f64>(&cases);
}
#[test]
#[cfg(f128_enabled)]
fn spec_tests_f128() {
let cases = [];
spec_test::<f128>(&cases);
}
}

74
vendor/libm/src/math/hypot.rs vendored Normal file
View File

@@ -0,0 +1,74 @@
use core::f64;
use super::sqrt;
const SPLIT: f64 = 134217728. + 1.; // 0x1p27 + 1 === (2 ^ 27) + 1
fn sq(x: f64) -> (f64, f64) {
let xh: f64;
let xl: f64;
let xc: f64;
xc = x * SPLIT;
xh = x - xc + xc;
xl = x - xh;
let hi = x * x;
let lo = xh * xh - hi + 2. * xh * xl + xl * xl;
(hi, lo)
}
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn hypot(mut x: f64, mut y: f64) -> f64 {
let x1p700 = f64::from_bits(0x6bb0000000000000); // 0x1p700 === 2 ^ 700
let x1p_700 = f64::from_bits(0x1430000000000000); // 0x1p-700 === 2 ^ -700
let mut uxi = x.to_bits();
let mut uyi = y.to_bits();
let uti;
let ex: i64;
let ey: i64;
let mut z: f64;
/* arrange |x| >= |y| */
uxi &= -1i64 as u64 >> 1;
uyi &= -1i64 as u64 >> 1;
if uxi < uyi {
uti = uxi;
uxi = uyi;
uyi = uti;
}
/* special cases */
ex = (uxi >> 52) as i64;
ey = (uyi >> 52) as i64;
x = f64::from_bits(uxi);
y = f64::from_bits(uyi);
/* note: hypot(inf,nan) == inf */
if ey == 0x7ff {
return y;
}
if ex == 0x7ff || uyi == 0 {
return x;
}
/* note: hypot(x,y) ~= x + y*y/x/2 with inexact for small y/x */
/* 64 difference is enough for ld80 double_t */
if ex - ey > 64 {
return x + y;
}
/* precise sqrt argument in nearest rounding mode without overflow */
/* xh*xh must not overflow and xl*xl must not underflow in sq */
z = 1.;
if ex > 0x3ff + 510 {
z = x1p700;
x *= x1p_700;
y *= x1p_700;
} else if ey < 0x3ff - 450 {
z = x1p_700;
x *= x1p700;
y *= x1p700;
}
let (hx, lx) = sq(x);
let (hy, ly) = sq(y);
z * sqrt(ly + lx + hy + hx)
}

43
vendor/libm/src/math/hypotf.rs vendored Normal file
View File

@@ -0,0 +1,43 @@
use core::f32;
use super::sqrtf;
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn hypotf(mut x: f32, mut y: f32) -> f32 {
let x1p90 = f32::from_bits(0x6c800000); // 0x1p90f === 2 ^ 90
let x1p_90 = f32::from_bits(0x12800000); // 0x1p-90f === 2 ^ -90
let mut uxi = x.to_bits();
let mut uyi = y.to_bits();
let uti;
let mut z: f32;
uxi &= -1i32 as u32 >> 1;
uyi &= -1i32 as u32 >> 1;
if uxi < uyi {
uti = uxi;
uxi = uyi;
uyi = uti;
}
x = f32::from_bits(uxi);
y = f32::from_bits(uyi);
if uyi == 0xff << 23 {
return y;
}
if uxi >= 0xff << 23 || uyi == 0 || uxi - uyi >= 25 << 23 {
return x + y;
}
z = 1.;
if uxi >= (0x7f + 60) << 23 {
z = x1p90;
x *= x1p_90;
y *= x1p_90;
} else if uyi < (0x7f - 60) << 23 {
z = x1p_90;
x *= x1p90;
y *= x1p90;
}
z * sqrtf((x as f64 * x as f64 + y as f64 * y as f64) as f32)
}

32
vendor/libm/src/math/ilogb.rs vendored Normal file
View File

@@ -0,0 +1,32 @@
const FP_ILOGBNAN: i32 = -1 - 0x7fffffff;
const FP_ILOGB0: i32 = FP_ILOGBNAN;
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn ilogb(x: f64) -> i32 {
let mut i: u64 = x.to_bits();
let e = ((i >> 52) & 0x7ff) as i32;
if e == 0 {
i <<= 12;
if i == 0 {
force_eval!(0.0 / 0.0);
return FP_ILOGB0;
}
/* subnormal x */
let mut e = -0x3ff;
while (i >> 63) == 0 {
e -= 1;
i <<= 1;
}
e
} else if e == 0x7ff {
force_eval!(0.0 / 0.0);
if (i << 12) != 0 {
FP_ILOGBNAN
} else {
i32::MAX
}
} else {
e - 0x3ff
}
}

28
vendor/libm/src/math/ilogbf.rs vendored Normal file
View File

@@ -0,0 +1,28 @@
const FP_ILOGBNAN: i32 = -1 - 0x7fffffff;
const FP_ILOGB0: i32 = FP_ILOGBNAN;
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn ilogbf(x: f32) -> i32 {
let mut i = x.to_bits();
let e = ((i >> 23) & 0xff) as i32;
if e == 0 {
i <<= 9;
if i == 0 {
force_eval!(0.0 / 0.0);
return FP_ILOGB0;
}
/* subnormal x */
let mut e = -0x7f;
while (i >> 31) == 0 {
e -= 1;
i <<= 1;
}
e
} else if e == 0xff {
force_eval!(0.0 / 0.0);
if (i << 9) != 0 { FP_ILOGBNAN } else { i32::MAX }
} else {
e - 0x7f
}
}

426
vendor/libm/src/math/j0.rs vendored Normal file
View File

@@ -0,0 +1,426 @@
/* origin: FreeBSD /usr/src/lib/msun/src/e_j0.c */
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunSoft, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
/* j0(x), y0(x)
* Bessel function of the first and second kinds of order zero.
* Method -- j0(x):
* 1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ...
* 2. Reduce x to |x| since j0(x)=j0(-x), and
* for x in (0,2)
* j0(x) = 1-z/4+ z^2*R0/S0, where z = x*x;
* (precision: |j0-1+z/4-z^2R0/S0 |<2**-63.67 )
* for x in (2,inf)
* j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0))
* where x0 = x-pi/4. It is better to compute sin(x0),cos(x0)
* as follow:
* cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4)
* = 1/sqrt(2) * (cos(x) + sin(x))
* sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4)
* = 1/sqrt(2) * (sin(x) - cos(x))
* (To avoid cancellation, use
* sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
* to compute the worse one.)
*
* 3 Special cases
* j0(nan)= nan
* j0(0) = 1
* j0(inf) = 0
*
* Method -- y0(x):
* 1. For x<2.
* Since
* y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x^2/4 - ...)
* therefore y0(x)-2/pi*j0(x)*ln(x) is an even function.
* We use the following function to approximate y0,
* y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x^2
* where
* U(z) = u00 + u01*z + ... + u06*z^6
* V(z) = 1 + v01*z + ... + v04*z^4
* with absolute approximation error bounded by 2**-72.
* Note: For tiny x, U/V = u0 and j0(x)~1, hence
* y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27)
* 2. For x>=2.
* y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0))
* where x0 = x-pi/4. It is better to compute sin(x0),cos(x0)
* by the method mentioned above.
* 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0.
*/
use super::{cos, fabs, get_high_word, get_low_word, log, sin, sqrt};
const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */
const TPI: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */
/* common method when |x|>=2 */
fn common(ix: u32, x: f64, y0: bool) -> f64 {
let s: f64;
let mut c: f64;
let mut ss: f64;
let mut cc: f64;
let z: f64;
/*
* j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x-pi/4)-q0(x)*sin(x-pi/4))
* y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x-pi/4)+q0(x)*cos(x-pi/4))
*
* sin(x-pi/4) = (sin(x) - cos(x))/sqrt(2)
* cos(x-pi/4) = (sin(x) + cos(x))/sqrt(2)
* sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
*/
s = sin(x);
c = cos(x);
if y0 {
c = -c;
}
cc = s + c;
/* avoid overflow in 2*x, big ulp error when x>=0x1p1023 */
if ix < 0x7fe00000 {
ss = s - c;
z = -cos(2.0 * x);
if s * c < 0.0 {
cc = z / ss;
} else {
ss = z / cc;
}
if ix < 0x48000000 {
if y0 {
ss = -ss;
}
cc = pzero(x) * cc - qzero(x) * ss;
}
}
return INVSQRTPI * cc / sqrt(x);
}
/* R0/S0 on [0, 2.00] */
const R02: f64 = 1.56249999999999947958e-02; /* 0x3F8FFFFF, 0xFFFFFFFD */
const R03: f64 = -1.89979294238854721751e-04; /* 0xBF28E6A5, 0xB61AC6E9 */
const R04: f64 = 1.82954049532700665670e-06; /* 0x3EBEB1D1, 0x0C503919 */
const R05: f64 = -4.61832688532103189199e-09; /* 0xBE33D5E7, 0x73D63FCE */
const S01: f64 = 1.56191029464890010492e-02; /* 0x3F8FFCE8, 0x82C8C2A4 */
const S02: f64 = 1.16926784663337450260e-04; /* 0x3F1EA6D2, 0xDD57DBF4 */
const S03: f64 = 5.13546550207318111446e-07; /* 0x3EA13B54, 0xCE84D5A9 */
const S04: f64 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */
/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn j0(mut x: f64) -> f64 {
let z: f64;
let r: f64;
let s: f64;
let mut ix: u32;
ix = get_high_word(x);
ix &= 0x7fffffff;
/* j0(+-inf)=0, j0(nan)=nan */
if ix >= 0x7ff00000 {
return 1.0 / (x * x);
}
x = fabs(x);
if ix >= 0x40000000 {
/* |x| >= 2 */
/* large ulp error near zeros: 2.4, 5.52, 8.6537,.. */
return common(ix, x, false);
}
/* 1 - x*x/4 + x*x*R(x^2)/S(x^2) */
if ix >= 0x3f200000 {
/* |x| >= 2**-13 */
/* up to 4ulp error close to 2 */
z = x * x;
r = z * (R02 + z * (R03 + z * (R04 + z * R05)));
s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * S04)));
return (1.0 + x / 2.0) * (1.0 - x / 2.0) + z * (r / s);
}
/* 1 - x*x/4 */
/* prevent underflow */
/* inexact should be raised when x!=0, this is not done correctly */
if ix >= 0x38000000 {
/* |x| >= 2**-127 */
x = 0.25 * x * x;
}
return 1.0 - x;
}
const U00: f64 = -7.38042951086872317523e-02; /* 0xBFB2E4D6, 0x99CBD01F */
const U01: f64 = 1.76666452509181115538e-01; /* 0x3FC69D01, 0x9DE9E3FC */
const U02: f64 = -1.38185671945596898896e-02; /* 0xBF8C4CE8, 0xB16CFA97 */
const U03: f64 = 3.47453432093683650238e-04; /* 0x3F36C54D, 0x20B29B6B */
const U04: f64 = -3.81407053724364161125e-06; /* 0xBECFFEA7, 0x73D25CAD */
const U05: f64 = 1.95590137035022920206e-08; /* 0x3E550057, 0x3B4EABD4 */
const U06: f64 = -3.98205194132103398453e-11; /* 0xBDC5E43D, 0x693FB3C8 */
const V01: f64 = 1.27304834834123699328e-02; /* 0x3F8A1270, 0x91C9C71A */
const V02: f64 = 7.60068627350353253702e-05; /* 0x3F13ECBB, 0xF578C6C1 */
const V03: f64 = 2.59150851840457805467e-07; /* 0x3E91642D, 0x7FF202FD */
const V04: f64 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */
/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn y0(x: f64) -> f64 {
let z: f64;
let u: f64;
let v: f64;
let ix: u32;
let lx: u32;
ix = get_high_word(x);
lx = get_low_word(x);
/* y0(nan)=nan, y0(<0)=nan, y0(0)=-inf, y0(inf)=0 */
if ((ix << 1) | lx) == 0 {
return -1.0 / 0.0;
}
if (ix >> 31) != 0 {
return 0.0 / 0.0;
}
if ix >= 0x7ff00000 {
return 1.0 / x;
}
if ix >= 0x40000000 {
/* x >= 2 */
/* large ulp errors near zeros: 3.958, 7.086,.. */
return common(ix, x, true);
}
/* U(x^2)/V(x^2) + (2/pi)*j0(x)*log(x) */
if ix >= 0x3e400000 {
/* x >= 2**-27 */
/* large ulp error near the first zero, x ~= 0.89 */
z = x * x;
u = U00 + z * (U01 + z * (U02 + z * (U03 + z * (U04 + z * (U05 + z * U06)))));
v = 1.0 + z * (V01 + z * (V02 + z * (V03 + z * V04)));
return u / v + TPI * (j0(x) * log(x));
}
return U00 + TPI * log(x);
}
/* The asymptotic expansions of pzero is
* 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x.
* For x >= 2, We approximate pzero by
* pzero(x) = 1 + (R/S)
* where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10
* S = 1 + pS0*s^2 + ... + pS4*s^10
* and
* | pzero(x)-1-R/S | <= 2 ** ( -60.26)
*/
const PR8: [f64; 6] = [
/* for x in [inf, 8]=1/[0,0.125] */
0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
-7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */
-8.08167041275349795626e+00, /* 0xC02029D0, 0xB44FA779 */
-2.57063105679704847262e+02, /* 0xC0701102, 0x7B19E863 */
-2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */
-5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */
];
const PS8: [f64; 5] = [
1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */
3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */
4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */
1.16752972564375915681e+05, /* 0x40FC810F, 0x8F9FA9BD */
4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */
];
const PR5: [f64; 6] = [
/* for x in [8,4.5454]=1/[0.125,0.22001] */
-1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */
-7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */
-4.15961064470587782438e+00, /* 0xC010A370, 0xF90C6BBF */
-6.76747652265167261021e+01, /* 0xC050EB2F, 0x5A7D1783 */
-3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */
-3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */
];
const PS5: [f64; 5] = [
6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */
1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */
5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */
9.62544514357774460223e+03, /* 0x40C2CCB8, 0xFA76FA38 */
2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */
];
const PR3: [f64; 6] = [
/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
-2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */
-7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */
-2.40903221549529611423e+00, /* 0xC00345B2, 0xAEA48074 */
-2.19659774734883086467e+01, /* 0xC035F74A, 0x4CB94E14 */
-5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */
-3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */
];
const PS3: [f64; 5] = [
3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */
3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */
1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */
1.12799679856907414432e+03, /* 0x40919FFC, 0xB8C39B7E */
1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */
];
const PR2: [f64; 6] = [
/* for x in [2.8570,2]=1/[0.3499,0.5] */
-8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */
-7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */
-1.45073846780952986357e+00, /* 0xBFF73639, 0x8A24A843 */
-7.63569613823527770791e+00, /* 0xC01E8AF3, 0xEDAFA7F3 */
-1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */
-3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */
];
const PS2: [f64; 5] = [
2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */
1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */
2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */
1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */
1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */
];
fn pzero(x: f64) -> f64 {
let p: &[f64; 6];
let q: &[f64; 5];
let z: f64;
let r: f64;
let s: f64;
let mut ix: u32;
ix = get_high_word(x);
ix &= 0x7fffffff;
if ix >= 0x40200000 {
p = &PR8;
q = &PS8;
} else if ix >= 0x40122E8B {
p = &PR5;
q = &PS5;
} else if ix >= 0x4006DB6D {
p = &PR3;
q = &PS3;
} else
/*ix >= 0x40000000*/
{
p = &PR2;
q = &PS2;
}
z = 1.0 / (x * x);
r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5]))));
s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4]))));
return 1.0 + r / s;
}
/* For x >= 8, the asymptotic expansions of qzero is
* -1/8 s + 75/1024 s^3 - ..., where s = 1/x.
* We approximate pzero by
* qzero(x) = s*(-1.25 + (R/S))
* where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10
* S = 1 + qS0*s^2 + ... + qS5*s^12
* and
* | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22)
*/
const QR8: [f64; 6] = [
/* for x in [inf, 8]=1/[0,0.125] */
0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */
1.17682064682252693899e+01, /* 0x40278952, 0x5BB334D6 */
5.57673380256401856059e+02, /* 0x40816D63, 0x15301825 */
8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */
3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */
];
const QS8: [f64; 6] = [
1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */
8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */
1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */
8.03309257119514397345e+05, /* 0x412883DA, 0x83A52B43 */
8.40501579819060512818e+05, /* 0x4129A66B, 0x28DE0B3D */
-3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */
];
const QR5: [f64; 6] = [
/* for x in [8,4.5454]=1/[0.125,0.22001] */
1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */
7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */
5.83563508962056953777e+00, /* 0x401757B0, 0xB9953DD3 */
1.35111577286449829671e+02, /* 0x4060E392, 0x0A8788E9 */
1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */
1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */
];
const QS5: [f64; 6] = [
8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */
2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */
1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */
5.67511122894947329769e+04, /* 0x40EBB5E3, 0x97E02372 */
3.59767538425114471465e+04, /* 0x40E19118, 0x1F7A54A0 */
-5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */
];
const QR3: [f64; 6] = [
/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */
7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */
3.34423137516170720929e+00, /* 0x400AC0FC, 0x61149CF5 */
4.26218440745412650017e+01, /* 0x40454F98, 0x962DAEDD */
1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */
1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */
];
const QS3: [f64; 6] = [
4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */
7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */
3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */
6.46042516752568917582e+03, /* 0x40B93C6C, 0xD7C76A28 */
2.51633368920368957333e+03, /* 0x40A3A8AA, 0xD94FB1C0 */
-1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */
];
const QR2: [f64; 6] = [
/* for x in [2.8570,2]=1/[0.3499,0.5] */
1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */
7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */
1.99819174093815998816e+00, /* 0x3FFFF897, 0xE727779C */
1.44956029347885735348e+01, /* 0x402CFDBF, 0xAAF96FE5 */
3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */
1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */
];
const QS2: [f64; 6] = [
3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */
2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */
8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */
8.82935845112488550512e+02, /* 0x408B977C, 0x9C5CC214 */
2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */
-5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */
];
fn qzero(x: f64) -> f64 {
let p: &[f64; 6];
let q: &[f64; 6];
let s: f64;
let r: f64;
let z: f64;
let mut ix: u32;
ix = get_high_word(x);
ix &= 0x7fffffff;
if ix >= 0x40200000 {
p = &QR8;
q = &QS8;
} else if ix >= 0x40122E8B {
p = &QR5;
q = &QS5;
} else if ix >= 0x4006DB6D {
p = &QR3;
q = &QS3;
} else
/*ix >= 0x40000000*/
{
p = &QR2;
q = &QS2;
}
z = 1.0 / (x * x);
r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5]))));
s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5])))));
return (-0.125 + r / s) / x;
}

Some files were not shown because too many files have changed in this diff Show More