libm-0.2.15/.cargo_vcs_info.json0000644000000001420000000000100120410ustar { "git": { "sha1": "a4c748f72a1dce652cc3e41c3a8425731bd1519a" }, "path_in_vcs": "libm" }libm-0.2.15/CHANGELOG.md000064400000000000000000000124411046102023000124470ustar 00000000000000# 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 libm-0.2.15/Cargo.lock0000644000000024670000000000100100300ustar # 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" libm-0.2.15/Cargo.toml0000644000000025100000000000100100400ustar # 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 "] 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"))'] libm-0.2.15/Cargo.toml.orig000064400000000000000000000026531046102023000135310ustar 00000000000000[package] authors = ["Jorge Aparicio "] categories = ["no-std"] description = "libm in pure Rust" documentation = "https://docs.rs/libm" keywords = ["libm", "math"] license = "MIT" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" version = "0.2.15" edition = "2021" rust-version = "1.63" [features] default = ["arch"] # Enable architecture-specific features such as SIMD or assembly routines. arch = [] # This tells the compiler to assume that a Nightly toolchain is being used and # that it should activate any useful Nightly things accordingly. unstable = ["unstable-intrinsics", "unstable-float"] # Enable calls to functions in `core::intrinsics` unstable-intrinsics = [] # Make some internal things public for testing. unstable-public-internals = [] # Enable the nightly-only `f16` and `f128`. unstable-float = [] # Used to prevent using any intrinsics or arch-specific code. # # HACK: this is a negative feature which is generally a bad idea in Cargo, but # we need it to be able to forbid other features when this crate is used in # Rust dependencies. Setting this overrides all features that may enable # hard float operations. force-soft-floats = [] [dev-dependencies] no-panic = "0.1.35" [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = [ # compiler-builtins sets this feature, but we use it in `libm` 'cfg(feature, values("compiler-builtins"))', ] } libm-0.2.15/LICENSE.txt000064400000000000000000000334101046102023000124600ustar 00000000000000rust-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. libm-0.2.15/README.md000064400000000000000000000023141046102023000121130ustar 00000000000000# `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 . ### Contribution Contributions are licensed under both the MIT license and the Apache License, Version 2.0, available at . 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. libm-0.2.15/build.rs000064400000000000000000000007261046102023000123060ustar 00000000000000use 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); } libm-0.2.15/configure.rs000064400000000000000000000155401046102023000131700ustar 00000000000000// 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, pub target_arch: String, pub target_env: String, pub target_family: Option, pub target_os: String, pub target_string: String, pub target_vendor: String, pub target_features: Vec, } 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: // let f16_enabled = match cfg.target_arch.as_str() { // Unsupported "arm64ec" => false, // Selection failure "s390x" => false, // Infinite recursion // FIXME(llvm): loongarch fixed by "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) "amdgpu" => false, // Unsupported "arm64ec" => false, // Selection failure "mips64" | "mips64r6" => false, // Selection failure "nvptx64" => false, // Selection failure "powerpc64" if &cfg.target_os == "aix" => false, // Selection failure "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"); } } libm-0.2.15/src/lib.rs000064400000000000000000000016711046102023000125440ustar 00000000000000//! 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::*; libm-0.2.15/src/libm_helper.rs000064400000000000000000000275621046102023000142670ustar 00000000000000use core::marker::PhantomData; use crate::*; /// Generic helper for libm functions, abstracting over f32 and f64.
/// # 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::::cos(0.0f32) == libm::cosf(0.0)); /// assert!(Libm::::sin(PI_F32) == libm::sinf(PI_F32)); /// /// assert!(Libm::::cos(0.0f64) == libm::cos(0.0)); /// assert!(Libm::::sin(PI_F64) == libm::sin(PI_F64)); /// ``` pub struct Libm(PhantomData); 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 libm-0.2.15/src/math/acos.rs000064400000000000000000000073421046102023000136550ustar 00000000000000/* 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) } libm-0.2.15/src/math/acosf.rs000064400000000000000000000042511046102023000140170ustar 00000000000000/* 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) } libm-0.2.15/src/math/acosh.rs000064400000000000000000000015431046102023000140220ustar 00000000000000use 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; } libm-0.2.15/src/math/acoshf.rs000064400000000000000000000014671046102023000141750ustar 00000000000000use 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; } libm-0.2.15/src/math/arch/aarch64.rs000064400000000000000000000056241046102023000150760ustar 00000000000000//! 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 } libm-0.2.15/src/math/arch/i586.rs000064400000000000000000000022261046102023000143340ustar 00000000000000//! 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; } } libm-0.2.15/src/math/arch/mod.rs000064400000000000000000000031611046102023000144170ustar 00000000000000//! 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}; } } libm-0.2.15/src/math/arch/wasm32.rs000064400000000000000000000016571046102023000147640ustar 00000000000000//! 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) } libm-0.2.15/src/math/arch/x86/detect.rs000064400000000000000000000222411046102023000155350ustar 00000000000000// 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 // Developer’s 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:?}" ); } } } libm-0.2.15/src/math/arch/x86/fma.rs000064400000000000000000000075551046102023000150430ustar 00000000000000//! 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 } libm-0.2.15/src/math/arch/x86.rs000064400000000000000000000014141046102023000142640ustar 00000000000000//! 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 } libm-0.2.15/src/math/asin.rs000064400000000000000000000102531046102023000136550ustar 00000000000000/* 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 } } libm-0.2.15/src/math/asinf.rs000064400000000000000000000037641046102023000140340ustar 00000000000000/* 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 } } libm-0.2.15/src/math/asinh.rs000064400000000000000000000021621046102023000140250ustar 00000000000000use 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 } } libm-0.2.15/src/math/asinhf.rs000064400000000000000000000021251046102023000141720ustar 00000000000000use 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 } } libm-0.2.15/src/math/atan.rs000064400000000000000000000131701046102023000136470ustar 00000000000000/* 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()); } } libm-0.2.15/src/math/atan2.rs000064400000000000000000000106351046102023000137340ustar 00000000000000/* 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); } } libm-0.2.15/src/math/atan2f.rs000064400000000000000000000054371046102023000141060ustar 00000000000000/* 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(-,-) */ } } libm-0.2.15/src/math/atanf.rs000064400000000000000000000060651046102023000140220ustar 00000000000000/* 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 } } libm-0.2.15/src/math/atanh.rs000064400000000000000000000016621046102023000140220ustar 00000000000000use 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 } } libm-0.2.15/src/math/atanhf.rs000064400000000000000000000016471046102023000141730ustar 00000000000000use 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 } } libm-0.2.15/src/math/cbrt.rs000064400000000000000000000165631046102023000136670ustar 00000000000000/* 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 { 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) ); } } } libm-0.2.15/src/math/cbrtf.rs000064400000000000000000000041451046102023000140260ustar 00000000000000/* 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 } libm-0.2.15/src/math/ceil.rs000064400000000000000000000022731046102023000136420ustar 00000000000000/// 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) } libm-0.2.15/src/math/copysign.rs000064400000000000000000000054231046102023000145610ustar 00000000000000/// 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: 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::(copysignf16); } #[test] fn spec_tests_f32() { spec_test::(copysignf); } #[test] fn spec_tests_f64() { spec_test::(copysign); } #[test] #[cfg(f128_enabled)] fn spec_tests_f128() { spec_test::(copysignf128); } } libm-0.2.15/src/math/copysignf.rs000064400000000000000000000004711046102023000147250ustar 00000000000000/// 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) } libm-0.2.15/src/math/copysignf128.rs000064400000000000000000000005001046102023000151510ustar 00000000000000/// 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) } libm-0.2.15/src/math/copysignf16.rs000064400000000000000000000004731046102023000150760ustar 00000000000000/// 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) } libm-0.2.15/src/math/cos.rs000064400000000000000000000044221046102023000135100ustar 00000000000000// 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), } } libm-0.2.15/src/math/cosf.rs000064400000000000000000000047101046102023000136560ustar 00000000000000/* 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), } } libm-0.2.15/src/math/cosh.rs000064400000000000000000000017151046102023000136620ustar 00000000000000use 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) } libm-0.2.15/src/math/coshf.rs000064400000000000000000000015721046102023000140310ustar 00000000000000use 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) } libm-0.2.15/src/math/erf.rs000064400000000000000000000305171046102023000135040ustar 00000000000000use 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 >= 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 } } libm-0.2.15/src/math/erff.rs000064400000000000000000000166301046102023000136520ustar 00000000000000/* 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 } } libm-0.2.15/src/math/exp.rs000064400000000000000000000117231046102023000135220ustar 00000000000000/* 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) } } libm-0.2.15/src/math/exp10.rs000064400000000000000000000014501046102023000136570ustar 00000000000000use 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); } libm-0.2.15/src/math/exp10f.rs000064400000000000000000000014251046102023000140270ustar 00000000000000use 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; } libm-0.2.15/src/math/exp2.rs000064400000000000000000000400441046102023000136020ustar 00000000000000// origin: FreeBSD /usr/src/lib/msun/src/s_exp2.c */ //- // Copyright (c) 2005 David Schultz // 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)); } libm-0.2.15/src/math/exp2f.rs000064400000000000000000000111611046102023000137460ustar 00000000000000// origin: FreeBSD /usr/src/lib/msun/src/s_exp2f.c //- // Copyright (c) 2005 David Schultz // 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 } libm-0.2.15/src/math/expf.rs000064400000000000000000000057001046102023000136660ustar 00000000000000/* 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) } } libm-0.2.15/src/math/expm1.rs000064400000000000000000000103501046102023000137530ustar 00000000000000/* 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); } } libm-0.2.15/src/math/expm1f.rs000064400000000000000000000075621046102023000141340ustar 00000000000000/* 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 } } libm-0.2.15/src/math/expo2.rs000064400000000000000000000010701046102023000137550ustar 00000000000000use 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 } libm-0.2.15/src/math/fabs.rs000064400000000000000000000057471046102023000136520ustar 00000000000000/// 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: 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::(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::(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::(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::(fabsf128); } } libm-0.2.15/src/math/fabsf.rs000064400000000000000000000021141046102023000140010ustar 00000000000000/// 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); } } } libm-0.2.15/src/math/fabsf128.rs000064400000000000000000000015311046102023000142360ustar 00000000000000/// 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); } } } libm-0.2.15/src/math/fabsf16.rs000064400000000000000000000015141046102023000141530ustar 00000000000000/// 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); } } } libm-0.2.15/src/math/fdim.rs000064400000000000000000000027101046102023000136410ustar 00000000000000/// 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) } libm-0.2.15/src/math/fdimf.rs000064400000000000000000000005451046102023000140130ustar 00000000000000/// 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) } libm-0.2.15/src/math/fdimf128.rs000064400000000000000000000005541046102023000142460ustar 00000000000000/// 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) } libm-0.2.15/src/math/fdimf16.rs000064400000000000000000000005471046102023000141640ustar 00000000000000/// 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) } libm-0.2.15/src/math/floor.rs000064400000000000000000000023351046102023000140460ustar 00000000000000/// 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); } libm-0.2.15/src/math/floorf.rs000064400000000000000000000005351046102023000142140ustar 00000000000000/// 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); } libm-0.2.15/src/math/floorf128.rs000064400000000000000000000003251046102023000144440ustar 00000000000000/// 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); } libm-0.2.15/src/math/floorf16.rs000064400000000000000000000003211046102023000143540ustar 00000000000000/// 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); } libm-0.2.15/src/math/fma.rs000064400000000000000000000121621046102023000134670ustar 00000000000000/* 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: impl Fn(F, F, F) -> F) where F: Float, F: CastFrom, F: CastFrom, F::Int: HInt, u32: CastInto, { 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::(fmaf); // Also do a small check that the non-widening version works for f32 (this should ideally // get tested some more). spec_test::(|x, y, z| generic::fma_round(x, y, z, Round::Nearest).val); } #[test] fn spec_test_f64() { spec_test::(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::(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, ); } } libm-0.2.15/src/math/fmin_fmax.rs000064400000000000000000000125161046102023000146730ustar 00000000000000/// 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: 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::(fminf16); } #[test] fn fmin_spec_tests_f32() { fmin_spec_test::(fminf); } #[test] fn fmin_spec_tests_f64() { fmin_spec_test::(fmin); } #[test] #[cfg(f128_enabled)] fn fmin_spec_tests_f128() { fmin_spec_test::(fminf128); } fn fmax_spec_test(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::(fmaxf16); } #[test] fn fmax_spec_tests_f32() { fmax_spec_test::(fmaxf); } #[test] fn fmax_spec_tests_f64() { fmax_spec_test::(fmax); } #[test] #[cfg(f128_enabled)] fn fmax_spec_tests_f128() { fmax_spec_test::(fmaxf128); } } libm-0.2.15/src/math/fminimum_fmaximum.rs000064400000000000000000000121461046102023000164520ustar 00000000000000/// 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: 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::(fminimumf16); } #[test] fn fminimum_spec_tests_f32() { fminimum_spec_test::(fminimumf); } #[test] fn fminimum_spec_tests_f64() { fminimum_spec_test::(fminimum); } #[test] #[cfg(f128_enabled)] fn fminimum_spec_tests_f128() { fminimum_spec_test::(fminimumf128); } fn fmaximum_spec_test(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::(fmaximumf16); } #[test] fn fmaximum_spec_tests_f32() { fmaximum_spec_test::(fmaximumf); } #[test] fn fmaximum_spec_tests_f64() { fmaximum_spec_test::(fmaximum); } #[test] #[cfg(f128_enabled)] fn fmaximum_spec_tests_f128() { fmaximum_spec_test::(fmaximumf128); } } libm-0.2.15/src/math/fminimum_fmaximum_num.rs000064400000000000000000000123221046102023000173250ustar 00000000000000/// 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: 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::(fminimum_numf16); } #[test] fn fminimum_num_spec_tests_f32() { fminimum_num_spec_test::(fminimum_numf); } #[test] fn fminimum_num_spec_tests_f64() { fminimum_num_spec_test::(fminimum_num); } #[test] #[cfg(f128_enabled)] fn fminimum_num_spec_tests_f128() { fminimum_num_spec_test::(fminimum_numf128); } fn fmaximum_num_spec_test(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::(fmaximum_numf16); } #[test] fn fmaximum_num_spec_tests_f32() { fmaximum_num_spec_test::(fmaximum_numf); } #[test] fn fmaximum_num_spec_tests_f64() { fmaximum_num_spec_test::(fmaximum_num); } #[test] #[cfg(f128_enabled)] fn fmaximum_num_spec_tests_f128() { fmaximum_num_spec_test::(fmaximum_numf128); } } libm-0.2.15/src/math/fmod.rs000064400000000000000000000016271046102023000136550ustar 00000000000000/// 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) } libm-0.2.15/src/math/fmodf.rs000064400000000000000000000003311046102023000140120ustar 00000000000000/// 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) } libm-0.2.15/src/math/fmodf128.rs000064400000000000000000000003371046102023000142530ustar 00000000000000/// 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) } libm-0.2.15/src/math/fmodf16.rs000064400000000000000000000003331046102023000141630ustar 00000000000000/// 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) } libm-0.2.15/src/math/frexp.rs000064400000000000000000000010501046102023000140420ustar 00000000000000#[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); } libm-0.2.15/src/math/frexpf.rs000064400000000000000000000010411046102023000142100ustar 00000000000000#[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) } libm-0.2.15/src/math/generic/ceil.rs000064400000000000000000000113421046102023000152530ustar 00000000000000/* 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(x: F) -> F { ceil_status(x).val } #[inline] pub fn ceil_status(x: F) -> FpResult { let zero = IntTy::::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(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::(&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::(&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::(&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::(&cases); } } libm-0.2.15/src/math/generic/copysign.rs000064400000000000000000000003711046102023000161720ustar 00000000000000use crate::support::Float; /// Copy the sign of `y` to `x`. #[inline] pub fn copysign(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) } libm-0.2.15/src/math/generic/fabs.rs000064400000000000000000000002521046102023000152500ustar 00000000000000use crate::support::Float; /// Absolute value. #[inline] pub fn fabs(x: F) -> F { let abs_mask = !F::SIGN_MASK; F::from_bits(x.to_bits() & abs_mask) } libm-0.2.15/src/math/generic/fdim.rs000064400000000000000000000001721046102023000152550ustar 00000000000000use crate::support::Float; #[inline] pub fn fdim(x: F, y: F) -> F { if x <= y { F::ZERO } else { x - y } } libm-0.2.15/src/math/generic/floor.rs000064400000000000000000000101431046102023000154560ustar 00000000000000/* 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(x: F) -> F { floor_status(x).val } #[inline] pub fn floor_status(x: F) -> FpResult { let zero = IntTy::::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(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::(&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::(&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::(&cases); } #[test] #[cfg(f128_enabled)] fn spec_tests_f128() { let cases = []; spec_test::(&cases); } } libm-0.2.15/src/math/generic/fma.rs000064400000000000000000000216751046102023000151140ustar 00000000000000/* 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(x: F, y: F, z: F, _round: Round) -> FpResult where F: Float, F: CastFrom, F: CastFrom, F::Int: HInt, u32: CastInto, { let one = IntTy::::ONE; let zero = IntTy::::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::::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::::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::::from(rlo < zlo); } else { // r -= z let (res, borrow) = rlo.overflowing_sub(zlo); rlo = res; rhi = rhi.wrapping_sub(zhi.wrapping_add(IntTy::::from(borrow))); if (rhi >> (F::BITS - 1)) != zero { rlo = rlo.signed().wrapping_neg().unsigned(); rhi = rhi.signed().wrapping_neg().unsigned() - IntTy::::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::::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::::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 { /// 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 Norm { /// 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 } } libm-0.2.15/src/math/generic/fma_wide.rs000064400000000000000000000042731046102023000161170ustar 00000000000000use 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(x: F, y: F, z: F, round: Round) -> FpResult where F: Float + HFloat, B: Float + DFloat, B::Int: CastInto, i32: CastFrom, { let one = IntTy::::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::::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()) } libm-0.2.15/src/math/generic/fmax.rs000064400000000000000000000014231046102023000152710ustar 00000000000000/* 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(x: F, y: F) -> F { let res = if x.is_nan() || x < y { y } else { x }; // Canonicalize res * F::ONE } libm-0.2.15/src/math/generic/fmaximum.rs000064400000000000000000000011771046102023000161670ustar 00000000000000/* 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(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 } libm-0.2.15/src/math/generic/fmaximum_num.rs000064400000000000000000000012541046102023000170420ustar 00000000000000/* 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(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 } libm-0.2.15/src/math/generic/fmin.rs000064400000000000000000000014231046102023000152670ustar 00000000000000/* 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(x: F, y: F) -> F { let res = if y.is_nan() || x < y { x } else { y }; // Canonicalize res * F::ONE } libm-0.2.15/src/math/generic/fminimum.rs000064400000000000000000000011771046102023000161650ustar 00000000000000/* 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(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 } libm-0.2.15/src/math/generic/fminimum_num.rs000064400000000000000000000012461046102023000170410ustar 00000000000000/* 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(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 } libm-0.2.15/src/math/generic/fmod.rs000064400000000000000000000040631046102023000152660ustar 00000000000000/* SPDX-License-Identifier: MIT OR Apache-2.0 */ use crate::support::{CastFrom, Float, Int, MinInt}; #[inline] pub fn fmod(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::(ux); let (div, ey) = into_sig_exp::(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(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(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 } libm-0.2.15/src/math/generic/mod.rs000064400000000000000000000015271046102023000151220ustar 00000000000000// 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; libm-0.2.15/src/math/generic/rint.rs000064400000000000000000000072441046102023000153210ustar 00000000000000/* 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(x: F, _round: Round) -> FpResult { 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(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::(&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::(&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::(&cases); } #[test] #[cfg(f128_enabled)] fn spec_tests_f128() { let cases = []; spec_test::(&cases); } } libm-0.2.15/src/math/generic/round.rs000064400000000000000000000042671046102023000154760ustar 00000000000000use super::{copysign, trunc}; use crate::support::{Float, MinInt}; #[inline] pub fn round(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); } } libm-0.2.15/src/math/generic/scalbn.rs000064400000000000000000000114101046102023000155750ustar 00000000000000use 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(mut x: F, mut n: i32) -> F where u32: CastInto, F::Int: CastFrom, F::Int: CastFrom, { let zero = IntTy::::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 } libm-0.2.15/src/math/generic/sqrt.rs000064400000000000000000000432341046102023000153350ustar 00000000000000/* 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(x: F) -> F where F: Float + SqrtHelper, F::Int: HInt, F::Int: From, F::Int: From, F::Int: CastInto, F::Int: CastInto, u32: CastInto, { sqrt_round(x, Round::Nearest).val } #[inline] pub fn sqrt_round(x: F, _round: Round) -> FpResult where F: Float + SqrtHelper, F::Int: HInt, F::Int: From, F::Int: From, F::Int: CastInto, F::Int: CastInto, u32: CastInto, { let zero = IntTy::::ZERO; let one = IntTy::::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::(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::(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::(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::::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(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(mut r_u0: I, mut s_u2: I, count: u32, final_set: bool) -> (I, I) where F: SqrtHelper, I: HInt + From, { 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 { /// 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 + CastFrom + From; /// Integer for the second set of rounds. If unused, set to the same type as the next set. type ISet2: HInt + From + From; /// 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() where F: Float + SqrtHelper, F::Int: HInt, F::Int: From, F::Int: From, F::Int: CastInto, F::Int: CastInto, u32: CastInto, { // 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::(); } #[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::(); } #[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::(); } #[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::(); } #[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() ); } } } libm-0.2.15/src/math/generic/trunc.rs000064400000000000000000000101031046102023000154640ustar 00000000000000/* SPDX-License-Identifier: MIT * origin: musl src/math/trunc.c */ use crate::support::{Float, FpResult, Int, IntTy, MinInt, Status}; #[inline] pub fn trunc(x: F) -> F { trunc_status(x).val } #[inline] pub fn trunc_status(x: F) -> FpResult { 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::::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(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::(&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::(&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::(&cases); } #[test] #[cfg(f128_enabled)] fn spec_tests_f128() { let cases = []; spec_test::(&cases); } } libm-0.2.15/src/math/hypot.rs000064400000000000000000000033641046102023000140730ustar 00000000000000use 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) } libm-0.2.15/src/math/hypotf.rs000064400000000000000000000017501046102023000142360ustar 00000000000000use 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) } libm-0.2.15/src/math/ilogb.rs000064400000000000000000000013161046102023000140170ustar 00000000000000const 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 } } libm-0.2.15/src/math/ilogbf.rs000064400000000000000000000012341046102023000141640ustar 00000000000000const 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 } } libm-0.2.15/src/math/j0.rs000064400000000000000000000367121046102023000132440ustar 00000000000000/* 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; } libm-0.2.15/src/math/j0f.rs000064400000000000000000000250551046102023000134100ustar 00000000000000/* origin: FreeBSD /usr/src/lib/msun/src/e_j0f.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::{cosf, fabsf, logf, sinf, sqrtf}; const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ const TPI: f32 = 6.3661974669e-01; /* 0x3f22f983 */ fn common(ix: u32, x: f32, y0: bool) -> f32 { let z: f32; let s: f32; let mut c: f32; let mut ss: f32; let mut cc: f32; /* * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) */ s = sinf(x); c = cosf(x); if y0 { c = -c; } cc = s + c; if ix < 0x7f000000 { ss = s - c; z = -cosf(2.0 * x); if s * c < 0.0 { cc = z / ss; } else { ss = z / cc; } if ix < 0x58800000 { if y0 { ss = -ss; } cc = pzerof(x) * cc - qzerof(x) * ss; } } return INVSQRTPI * cc / sqrtf(x); } /* R0/S0 on [0, 2.00] */ const R02: f32 = 1.5625000000e-02; /* 0x3c800000 */ const R03: f32 = -1.8997929874e-04; /* 0xb947352e */ const R04: f32 = 1.8295404516e-06; /* 0x35f58e88 */ const R05: f32 = -4.6183270541e-09; /* 0xb19eaf3c */ const S01: f32 = 1.5619102865e-02; /* 0x3c7fe744 */ const S02: f32 = 1.1692678527e-04; /* 0x38f53697 */ const S03: f32 = 5.1354652442e-07; /* 0x3509daa6 */ const S04: f32 = 1.1661400734e-09; /* 0x30a045e8 */ /// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn j0f(mut x: f32) -> f32 { let z: f32; let r: f32; let s: f32; let mut ix: u32; ix = x.to_bits(); ix &= 0x7fffffff; if ix >= 0x7f800000 { return 1.0 / (x * x); } x = fabsf(x); if ix >= 0x40000000 { /* |x| >= 2 */ /* large ulp error near zeros */ return common(ix, x, false); } if ix >= 0x3a000000 { /* |x| >= 2**-11 */ /* up to 4ulp error near 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); } if ix >= 0x21800000 { /* |x| >= 2**-60 */ x = 0.25 * x * x; } return 1.0 - x; } const U00: f32 = -7.3804296553e-02; /* 0xbd9726b5 */ const U01: f32 = 1.7666645348e-01; /* 0x3e34e80d */ const U02: f32 = -1.3818567619e-02; /* 0xbc626746 */ const U03: f32 = 3.4745343146e-04; /* 0x39b62a69 */ const U04: f32 = -3.8140706238e-06; /* 0xb67ff53c */ const U05: f32 = 1.9559013964e-08; /* 0x32a802ba */ const U06: f32 = -3.9820518410e-11; /* 0xae2f21eb */ const V01: f32 = 1.2730483897e-02; /* 0x3c509385 */ const V02: f32 = 7.6006865129e-05; /* 0x389f65e0 */ const V03: f32 = 2.5915085189e-07; /* 0x348b216c */ const V04: f32 = 4.4111031494e-10; /* 0x2ff280c2 */ /// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn y0f(x: f32) -> f32 { let z: f32; let u: f32; let v: f32; let ix: u32; ix = x.to_bits(); if (ix & 0x7fffffff) == 0 { return -1.0 / 0.0; } if (ix >> 31) != 0 { return 0.0 / 0.0; } if ix >= 0x7f800000 { return 1.0 / x; } if ix >= 0x40000000 { /* |x| >= 2.0 */ /* large ulp error near zeros */ return common(ix, x, true); } if ix >= 0x39000000 { /* x >= 2**-13 */ /* large ulp error at 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 * (j0f(x) * logf(x)); } return U00 + TPI * logf(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: [f32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.0000000000e+00, /* 0x00000000 */ -7.0312500000e-02, /* 0xbd900000 */ -8.0816707611e+00, /* 0xc1014e86 */ -2.5706311035e+02, /* 0xc3808814 */ -2.4852163086e+03, /* 0xc51b5376 */ -5.2530439453e+03, /* 0xc5a4285a */ ]; const PS8: [f32; 5] = [ 1.1653436279e+02, /* 0x42e91198 */ 3.8337448730e+03, /* 0x456f9beb */ 4.0597855469e+04, /* 0x471e95db */ 1.1675296875e+05, /* 0x47e4087c */ 4.7627726562e+04, /* 0x473a0bba */ ]; const PR5: [f32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ -1.1412546255e-11, /* 0xad48c58a */ -7.0312492549e-02, /* 0xbd8fffff */ -4.1596107483e+00, /* 0xc0851b88 */ -6.7674766541e+01, /* 0xc287597b */ -3.3123129272e+02, /* 0xc3a59d9b */ -3.4643338013e+02, /* 0xc3ad3779 */ ]; const PS5: [f32; 5] = [ 6.0753936768e+01, /* 0x42730408 */ 1.0512523193e+03, /* 0x44836813 */ 5.9789707031e+03, /* 0x45bad7c4 */ 9.6254453125e+03, /* 0x461665c8 */ 2.4060581055e+03, /* 0x451660ee */ ]; const PR3: [f32; 6] = [ /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ -2.5470459075e-09, /* 0xb12f081b */ -7.0311963558e-02, /* 0xbd8fffb8 */ -2.4090321064e+00, /* 0xc01a2d95 */ -2.1965976715e+01, /* 0xc1afba52 */ -5.8079170227e+01, /* 0xc2685112 */ -3.1447946548e+01, /* 0xc1fb9565 */ ]; const PS3: [f32; 5] = [ 3.5856033325e+01, /* 0x420f6c94 */ 3.6151397705e+02, /* 0x43b4c1ca */ 1.1936077881e+03, /* 0x44953373 */ 1.1279968262e+03, /* 0x448cffe6 */ 1.7358093262e+02, /* 0x432d94b8 */ ]; const PR2: [f32; 6] = [ /* for x in [2.8570,2]=1/[0.3499,0.5] */ -8.8753431271e-08, /* 0xb3be98b7 */ -7.0303097367e-02, /* 0xbd8ffb12 */ -1.4507384300e+00, /* 0xbfb9b1cc */ -7.6356959343e+00, /* 0xc0f4579f */ -1.1193166733e+01, /* 0xc1331736 */ -3.2336456776e+00, /* 0xc04ef40d */ ]; const PS2: [f32; 5] = [ 2.2220300674e+01, /* 0x41b1c32d */ 1.3620678711e+02, /* 0x430834f0 */ 2.7047027588e+02, /* 0x43873c32 */ 1.5387539673e+02, /* 0x4319e01a */ 1.4657617569e+01, /* 0x416a859a */ ]; fn pzerof(x: f32) -> f32 { let p: &[f32; 6]; let q: &[f32; 5]; let z: f32; let r: f32; let s: f32; let mut ix: u32; ix = x.to_bits(); ix &= 0x7fffffff; if ix >= 0x41000000 { p = &PR8; q = &PS8; } else if ix >= 0x409173eb { p = &PR5; q = &PS5; } else if ix >= 0x4036d917 { 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: [f32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.0000000000e+00, /* 0x00000000 */ 7.3242187500e-02, /* 0x3d960000 */ 1.1768206596e+01, /* 0x413c4a93 */ 5.5767340088e+02, /* 0x440b6b19 */ 8.8591972656e+03, /* 0x460a6cca */ 3.7014625000e+04, /* 0x471096a0 */ ]; const QS8: [f32; 6] = [ 1.6377603149e+02, /* 0x4323c6aa */ 8.0983447266e+03, /* 0x45fd12c2 */ 1.4253829688e+05, /* 0x480b3293 */ 8.0330925000e+05, /* 0x49441ed4 */ 8.4050156250e+05, /* 0x494d3359 */ -3.4389928125e+05, /* 0xc8a7eb69 */ ]; const QR5: [f32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ 1.8408595828e-11, /* 0x2da1ec79 */ 7.3242180049e-02, /* 0x3d95ffff */ 5.8356351852e+00, /* 0x40babd86 */ 1.3511157227e+02, /* 0x43071c90 */ 1.0272437744e+03, /* 0x448067cd */ 1.9899779053e+03, /* 0x44f8bf4b */ ]; const QS5: [f32; 6] = [ 8.2776611328e+01, /* 0x42a58da0 */ 2.0778142090e+03, /* 0x4501dd07 */ 1.8847289062e+04, /* 0x46933e94 */ 5.6751113281e+04, /* 0x475daf1d */ 3.5976753906e+04, /* 0x470c88c1 */ -5.3543427734e+03, /* 0xc5a752be */ ]; const QR3: [f32; 6] = [ /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ 4.3774099900e-09, /* 0x3196681b */ 7.3241114616e-02, /* 0x3d95ff70 */ 3.3442313671e+00, /* 0x405607e3 */ 4.2621845245e+01, /* 0x422a7cc5 */ 1.7080809021e+02, /* 0x432acedf */ 1.6673394775e+02, /* 0x4326bbe4 */ ]; const QS3: [f32; 6] = [ 4.8758872986e+01, /* 0x42430916 */ 7.0968920898e+02, /* 0x44316c1c */ 3.7041481934e+03, /* 0x4567825f */ 6.4604252930e+03, /* 0x45c9e367 */ 2.5163337402e+03, /* 0x451d4557 */ -1.4924745178e+02, /* 0xc3153f59 */ ]; const QR2: [f32; 6] = [ /* for x in [2.8570,2]=1/[0.3499,0.5] */ 1.5044444979e-07, /* 0x342189db */ 7.3223426938e-02, /* 0x3d95f62a */ 1.9981917143e+00, /* 0x3fffc4bf */ 1.4495602608e+01, /* 0x4167edfd */ 3.1666231155e+01, /* 0x41fd5471 */ 1.6252708435e+01, /* 0x4182058c */ ]; const QS2: [f32; 6] = [ 3.0365585327e+01, /* 0x41f2ecb8 */ 2.6934811401e+02, /* 0x4386ac8f */ 8.4478375244e+02, /* 0x44533229 */ 8.8293585205e+02, /* 0x445cbbe5 */ 2.1266638184e+02, /* 0x4354aa98 */ -5.3109550476e+00, /* 0xc0a9f358 */ ]; fn qzerof(x: f32) -> f32 { let p: &[f32; 6]; let q: &[f32; 6]; let s: f32; let r: f32; let z: f32; let mut ix: u32; ix = x.to_bits(); ix &= 0x7fffffff; if ix >= 0x41000000 { p = &QR8; q = &QS8; } else if ix >= 0x409173eb { p = &QR5; q = &QS5; } else if ix >= 0x4036d917 { 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; } libm-0.2.15/src/math/j1.rs000064400000000000000000000355721046102023000132500ustar 00000000000000/* origin: FreeBSD /usr/src/lib/msun/src/e_j1.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. * ==================================================== */ /* j1(x), y1(x) * Bessel function of the first and second kinds of order zero. * Method -- j1(x): * 1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ... * 2. Reduce x to |x| since j1(x)=-j1(-x), and * for x in (0,2) * j1(x) = x/2 + x*z*R0/S0, where z = x*x; * (precision: |j1/x - 1/2 - R0/S0 |<2**-61.51 ) * for x in (2,inf) * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1)) * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) * as follow: * cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) * = 1/sqrt(2) * (sin(x) - cos(x)) * sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/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 * j1(nan)= nan * j1(0) = 0 * j1(inf) = 0 * * Method -- y1(x): * 1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN * 2. For x<2. * Since * y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x^3-...) * therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function. * We use the following function to approximate y1, * y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x^2 * where for x in [0,2] (abs err less than 2**-65.89) * U(z) = U0[0] + U0[1]*z + ... + U0[4]*z^4 * V(z) = 1 + v0[0]*z + ... + v0[4]*z^5 * Note: For tiny x, 1/x dominate y1 and hence * y1(tiny) = -2/pi/tiny, (choose tiny<2**-54) * 3. For x>=2. * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) * by method mentioned above. */ 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 */ fn common(ix: u32, x: f64, y1: bool, sign: bool) -> f64 { let z: f64; let mut s: f64; let c: f64; let mut ss: f64; let mut cc: f64; /* * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x-3pi/4)-q1(x)*sin(x-3pi/4)) * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x-3pi/4)+q1(x)*cos(x-3pi/4)) * * sin(x-3pi/4) = -(sin(x) + cos(x))/sqrt(2) * cos(x-3pi/4) = (sin(x) - cos(x))/sqrt(2) * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) */ s = sin(x); if y1 { s = -s; } c = cos(x); cc = s - c; if ix < 0x7fe00000 { /* avoid overflow in 2*x */ ss = -s - c; z = cos(2.0 * x); if s * c > 0.0 { cc = z / ss; } else { ss = z / cc; } if ix < 0x48000000 { if y1 { ss = -ss; } cc = pone(x) * cc - qone(x) * ss; } } if sign { cc = -cc; } return INVSQRTPI * cc / sqrt(x); } /* R0/S0 on [0,2] */ const R00: f64 = -6.25000000000000000000e-02; /* 0xBFB00000, 0x00000000 */ const R01: f64 = 1.40705666955189706048e-03; /* 0x3F570D9F, 0x98472C61 */ const R02: f64 = -1.59955631084035597520e-05; /* 0xBEF0C5C6, 0xBA169668 */ const R03: f64 = 4.96727999609584448412e-08; /* 0x3E6AAAFA, 0x46CA0BD9 */ const S01: f64 = 1.91537599538363460805e-02; /* 0x3F939D0B, 0x12637E53 */ const S02: f64 = 1.85946785588630915560e-04; /* 0x3F285F56, 0xB9CDF664 */ const S03: f64 = 1.17718464042623683263e-06; /* 0x3EB3BFF8, 0x333F8498 */ const S04: f64 = 5.04636257076217042715e-09; /* 0x3E35AC88, 0xC97DFF2C */ const S05: f64 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ /// First 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 j1(x: f64) -> f64 { let mut z: f64; let r: f64; let s: f64; let mut ix: u32; let sign: bool; ix = get_high_word(x); sign = (ix >> 31) != 0; ix &= 0x7fffffff; if ix >= 0x7ff00000 { return 1.0 / (x * x); } if ix >= 0x40000000 { /* |x| >= 2 */ return common(ix, fabs(x), false, sign); } if ix >= 0x38000000 { /* |x| >= 2**-127 */ z = x * x; r = z * (R00 + z * (R01 + z * (R02 + z * R03))); s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * (S04 + z * S05)))); z = r / s; } else { /* avoid underflow, raise inexact if x!=0 */ z = x; } return (0.5 + z) * x; } const U0: [f64; 5] = [ -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */ 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */ -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */ 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */ -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */ ]; const V0: [f64; 5] = [ 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */ 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */ 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */ 6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */ 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */ ]; /// First 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 y1(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); /* y1(nan)=nan, y1(<0)=nan, y1(0)=-inf, y1(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 */ return common(ix, x, true, false); } if ix < 0x3c900000 { /* x < 2**-54 */ return -TPI / x; } z = x * x; u = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); v = 1.0 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); return x * (u / v) + TPI * (j1(x) * log(x) - 1.0 / x); } /* For x >= 8, the asymptotic expansions of pone is * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. * We approximate pone by * pone(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 * | pone(x)-1-R/S | <= 2 ** ( -60.06) */ const PR8: [f64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */ 1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */ 4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */ 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */ 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */ ]; const PS8: [f64; 5] = [ 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */ 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */ 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */ 9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */ 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */ ]; const PR5: [f64; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */ 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */ 6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */ 1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */ 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */ 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */ ]; const PS5: [f64; 5] = [ 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */ 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */ 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */ 7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */ 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */ ]; const PR3: [f64; 6] = [ 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */ 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */ 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */ 3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */ 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */ 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */ ]; const PS3: [f64; 5] = [ 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */ 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */ 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */ 8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */ 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */ ]; const PR2: [f64; 6] = [ /* for x in [2.8570,2]=1/[0.3499,0.5] */ 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */ 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */ 2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */ 1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */ 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */ 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */ ]; const PS2: [f64; 5] = [ 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */ 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */ 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */ 1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */ 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */ ]; fn pone(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 qone is * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. * We approximate pone by * qone(x) = s*(0.375 + (R/S)) * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 * S = 1 + qs1*s^2 + ... + qs6*s^12 * and * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) */ const QR8: [f64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */ -1.62717534544589987888e+01, /* 0xC0304591, 0xA26779F7 */ -7.59601722513950107896e+02, /* 0xC087BCD0, 0x53E4B576 */ -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */ -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */ ]; const QS8: [f64; 6] = [ 1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */ 7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */ 1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */ 7.19657723683240939863e+05, /* 0x4125F653, 0x72869C19 */ 6.66601232617776375264e+05, /* 0x412457D2, 0x7719AD5C */ -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */ ]; const QR5: [f64; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */ -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */ -8.05644828123936029840e+00, /* 0xC0201CE6, 0xCA03AD4B */ -1.83669607474888380239e+02, /* 0xC066F56D, 0x6CA7B9B0 */ -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */ -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */ ]; const QS5: [f64; 6] = [ 8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */ 1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */ 1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */ 4.98514270910352279316e+04, /* 0x40E8576D, 0xAABAD197 */ 2.79480751638918118260e+04, /* 0x40DB4B04, 0xCF7C364B */ -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */ ]; const QR3: [f64; 6] = [ -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */ -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */ -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */ -5.78472216562783643212e+01, /* 0xC04CEC71, 0xC25D16DA */ -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */ -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */ ]; const QS3: [f64; 6] = [ 4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */ 6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */ 3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */ 5.54772909720722782367e+03, /* 0x40B5ABBA, 0xA61D54A6 */ 1.90311919338810798763e+03, /* 0x409DBC7A, 0x0DD4DF4B */ -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */ ]; const QR2: [f64; 6] = [ /* for x in [2.8570,2]=1/[0.3499,0.5] */ -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */ -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */ -2.75220568278187460720e+00, /* 0xC0060484, 0x69BB4EDA */ -1.96636162643703720221e+01, /* 0xC033A9E2, 0xC168907F */ -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */ -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */ ]; const QS2: [f64; 6] = [ 2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */ 2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */ 7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */ 7.39393205320467245656e+02, /* 0x40871B25, 0x48D4C029 */ 1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */ -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */ ]; fn qone(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.375 + r / s) / x; } libm-0.2.15/src/math/j1f.rs000064400000000000000000000253541046102023000134130ustar 00000000000000/* origin: FreeBSD /usr/src/lib/msun/src/e_j1f.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::{cosf, fabsf, logf, sinf, sqrtf}; const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ const TPI: f32 = 6.3661974669e-01; /* 0x3f22f983 */ fn common(ix: u32, x: f32, y1: bool, sign: bool) -> f32 { let z: f64; let mut s: f64; let c: f64; let mut ss: f64; let mut cc: f64; s = sinf(x) as f64; if y1 { s = -s; } c = cosf(x) as f64; cc = s - c; if ix < 0x7f000000 { ss = -s - c; z = cosf(2.0 * x) as f64; if s * c > 0.0 { cc = z / ss; } else { ss = z / cc; } if ix < 0x58800000 { if y1 { ss = -ss; } cc = (ponef(x) as f64) * cc - (qonef(x) as f64) * ss; } } if sign { cc = -cc; } return (((INVSQRTPI as f64) * cc) / (sqrtf(x) as f64)) as f32; } /* R0/S0 on [0,2] */ const R00: f32 = -6.2500000000e-02; /* 0xbd800000 */ const R01: f32 = 1.4070566976e-03; /* 0x3ab86cfd */ const R02: f32 = -1.5995563444e-05; /* 0xb7862e36 */ const R03: f32 = 4.9672799207e-08; /* 0x335557d2 */ const S01: f32 = 1.9153760746e-02; /* 0x3c9ce859 */ const S02: f32 = 1.8594678841e-04; /* 0x3942fab6 */ const S03: f32 = 1.1771846857e-06; /* 0x359dffc2 */ const S04: f32 = 5.0463624390e-09; /* 0x31ad6446 */ const S05: f32 = 1.2354227016e-11; /* 0x2d59567e */ /// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn j1f(x: f32) -> f32 { let mut z: f32; let r: f32; let s: f32; let mut ix: u32; let sign: bool; ix = x.to_bits(); sign = (ix >> 31) != 0; ix &= 0x7fffffff; if ix >= 0x7f800000 { return 1.0 / (x * x); } if ix >= 0x40000000 { /* |x| >= 2 */ return common(ix, fabsf(x), false, sign); } if ix >= 0x39000000 { /* |x| >= 2**-13 */ z = x * x; r = z * (R00 + z * (R01 + z * (R02 + z * R03))); s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * (S04 + z * S05)))); z = 0.5 + r / s; } else { z = 0.5; } return z * x; } const U0: [f32; 5] = [ -1.9605709612e-01, /* 0xbe48c331 */ 5.0443872809e-02, /* 0x3d4e9e3c */ -1.9125689287e-03, /* 0xbafaaf2a */ 2.3525259166e-05, /* 0x37c5581c */ -9.1909917899e-08, /* 0xb3c56003 */ ]; const V0: [f32; 5] = [ 1.9916731864e-02, /* 0x3ca3286a */ 2.0255257550e-04, /* 0x3954644b */ 1.3560879779e-06, /* 0x35b602d4 */ 6.2274145840e-09, /* 0x31d5f8eb */ 1.6655924903e-11, /* 0x2d9281cf */ ]; /// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn y1f(x: f32) -> f32 { let z: f32; let u: f32; let v: f32; let ix: u32; ix = x.to_bits(); if (ix & 0x7fffffff) == 0 { return -1.0 / 0.0; } if (ix >> 31) != 0 { return 0.0 / 0.0; } if ix >= 0x7f800000 { return 1.0 / x; } if ix >= 0x40000000 { /* |x| >= 2.0 */ return common(ix, x, true, false); } if ix < 0x33000000 { /* x < 2**-25 */ return -TPI / x; } z = x * x; u = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); v = 1.0 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); return x * (u / v) + TPI * (j1f(x) * logf(x) - 1.0 / x); } /* For x >= 8, the asymptotic expansions of pone is * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. * We approximate pone by * pone(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 * | pone(x)-1-R/S | <= 2 ** ( -60.06) */ const PR8: [f32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.0000000000e+00, /* 0x00000000 */ 1.1718750000e-01, /* 0x3df00000 */ 1.3239480972e+01, /* 0x4153d4ea */ 4.1205184937e+02, /* 0x43ce06a3 */ 3.8747453613e+03, /* 0x45722bed */ 7.9144794922e+03, /* 0x45f753d6 */ ]; const PS8: [f32; 5] = [ 1.1420736694e+02, /* 0x42e46a2c */ 3.6509309082e+03, /* 0x45642ee5 */ 3.6956207031e+04, /* 0x47105c35 */ 9.7602796875e+04, /* 0x47bea166 */ 3.0804271484e+04, /* 0x46f0a88b */ ]; const PR5: [f32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ 1.3199052094e-11, /* 0x2d68333f */ 1.1718749255e-01, /* 0x3defffff */ 6.8027510643e+00, /* 0x40d9b023 */ 1.0830818176e+02, /* 0x42d89dca */ 5.1763616943e+02, /* 0x440168b7 */ 5.2871520996e+02, /* 0x44042dc6 */ ]; const PS5: [f32; 5] = [ 5.9280597687e+01, /* 0x426d1f55 */ 9.9140142822e+02, /* 0x4477d9b1 */ 5.3532670898e+03, /* 0x45a74a23 */ 7.8446904297e+03, /* 0x45f52586 */ 1.5040468750e+03, /* 0x44bc0180 */ ]; const PR3: [f32; 6] = [ 3.0250391081e-09, /* 0x314fe10d */ 1.1718686670e-01, /* 0x3defffab */ 3.9329774380e+00, /* 0x407bb5e7 */ 3.5119403839e+01, /* 0x420c7a45 */ 9.1055007935e+01, /* 0x42b61c2a */ 4.8559066772e+01, /* 0x42423c7c */ ]; const PS3: [f32; 5] = [ 3.4791309357e+01, /* 0x420b2a4d */ 3.3676245117e+02, /* 0x43a86198 */ 1.0468714600e+03, /* 0x4482dbe3 */ 8.9081134033e+02, /* 0x445eb3ed */ 1.0378793335e+02, /* 0x42cf936c */ ]; const PR2: [f32; 6] = [ /* for x in [2.8570,2]=1/[0.3499,0.5] */ 1.0771083225e-07, /* 0x33e74ea8 */ 1.1717621982e-01, /* 0x3deffa16 */ 2.3685150146e+00, /* 0x401795c0 */ 1.2242610931e+01, /* 0x4143e1bc */ 1.7693971634e+01, /* 0x418d8d41 */ 5.0735230446e+00, /* 0x40a25a4d */ ]; const PS2: [f32; 5] = [ 2.1436485291e+01, /* 0x41ab7dec */ 1.2529022980e+02, /* 0x42fa9499 */ 2.3227647400e+02, /* 0x436846c7 */ 1.1767937469e+02, /* 0x42eb5bd7 */ 8.3646392822e+00, /* 0x4105d590 */ ]; fn ponef(x: f32) -> f32 { let p: &[f32; 6]; let q: &[f32; 5]; let z: f32; let r: f32; let s: f32; let mut ix: u32; ix = x.to_bits(); ix &= 0x7fffffff; if ix >= 0x41000000 { p = &PR8; q = &PS8; } else if ix >= 0x409173eb { p = &PR5; q = &PS5; } else if ix >= 0x4036d917 { 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 qone is * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. * We approximate pone by * qone(x) = s*(0.375 + (R/S)) * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 * S = 1 + qs1*s^2 + ... + qs6*s^12 * and * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) */ const QR8: [f32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.0000000000e+00, /* 0x00000000 */ -1.0253906250e-01, /* 0xbdd20000 */ -1.6271753311e+01, /* 0xc1822c8d */ -7.5960174561e+02, /* 0xc43de683 */ -1.1849806641e+04, /* 0xc639273a */ -4.8438511719e+04, /* 0xc73d3683 */ ]; const QS8: [f32; 6] = [ 1.6139537048e+02, /* 0x43216537 */ 7.8253862305e+03, /* 0x45f48b17 */ 1.3387534375e+05, /* 0x4802bcd6 */ 7.1965775000e+05, /* 0x492fb29c */ 6.6660125000e+05, /* 0x4922be94 */ -2.9449025000e+05, /* 0xc88fcb48 */ ]; const QR5: [f32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ -2.0897993405e-11, /* 0xadb7d219 */ -1.0253904760e-01, /* 0xbdd1fffe */ -8.0564479828e+00, /* 0xc100e736 */ -1.8366960144e+02, /* 0xc337ab6b */ -1.3731937256e+03, /* 0xc4aba633 */ -2.6124443359e+03, /* 0xc523471c */ ]; const QS5: [f32; 6] = [ 8.1276550293e+01, /* 0x42a28d98 */ 1.9917987061e+03, /* 0x44f8f98f */ 1.7468484375e+04, /* 0x468878f8 */ 4.9851425781e+04, /* 0x4742bb6d */ 2.7948074219e+04, /* 0x46da5826 */ -4.7191835938e+03, /* 0xc5937978 */ ]; const QR3: [f32; 6] = [ -5.0783124372e-09, /* 0xb1ae7d4f */ -1.0253783315e-01, /* 0xbdd1ff5b */ -4.6101160049e+00, /* 0xc0938612 */ -5.7847221375e+01, /* 0xc267638e */ -2.2824453735e+02, /* 0xc3643e9a */ -2.1921012878e+02, /* 0xc35b35cb */ ]; const QS3: [f32; 6] = [ 4.7665153503e+01, /* 0x423ea91e */ 6.7386511230e+02, /* 0x4428775e */ 3.3801528320e+03, /* 0x45534272 */ 5.5477290039e+03, /* 0x45ad5dd5 */ 1.9031191406e+03, /* 0x44ede3d0 */ -1.3520118713e+02, /* 0xc3073381 */ ]; const QR2: [f32; 6] = [ /* for x in [2.8570,2]=1/[0.3499,0.5] */ -1.7838172539e-07, /* 0xb43f8932 */ -1.0251704603e-01, /* 0xbdd1f475 */ -2.7522056103e+00, /* 0xc0302423 */ -1.9663616180e+01, /* 0xc19d4f16 */ -4.2325313568e+01, /* 0xc2294d1f */ -2.1371921539e+01, /* 0xc1aaf9b2 */ ]; const QS2: [f32; 6] = [ 2.9533363342e+01, /* 0x41ec4454 */ 2.5298155212e+02, /* 0x437cfb47 */ 7.5750280762e+02, /* 0x443d602e */ 7.3939318848e+02, /* 0x4438d92a */ 1.5594900513e+02, /* 0x431bf2f2 */ -4.9594988823e+00, /* 0xc09eb437 */ ]; fn qonef(x: f32) -> f32 { let p: &[f32; 6]; let q: &[f32; 6]; let s: f32; let r: f32; let z: f32; let mut ix: u32; ix = x.to_bits(); ix &= 0x7fffffff; if ix >= 0x41000000 { p = &QR8; q = &QS8; } else if ix >= 0x409173eb { p = &QR5; q = &QS5; } else if ix >= 0x4036d917 { 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.375 + r / s) / 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::{j1f, y1f}; #[test] fn test_j1f_2488() { // 0x401F3E49 assert_eq!(j1f(2.4881766_f32), 0.49999475_f32); } #[test] fn test_y1f_2002() { //allow slightly different result on x87 let res = y1f(2.0000002_f32); if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) && (res == -0.10703231_f32) { return; } assert_eq!(res, -0.10703229_f32); } } libm-0.2.15/src/math/jn.rs000064400000000000000000000234301046102023000133330ustar 00000000000000/* origin: FreeBSD /usr/src/lib/msun/src/e_jn.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. * ==================================================== */ /* * jn(n, x), yn(n, x) * floating point Bessel's function of the 1st and 2nd kind * of order n * * Special cases: * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal; * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal. * Note 2. About jn(n,x), yn(n,x) * For n=0, j0(x) is called, * for n=1, j1(x) is called, * for n<=x, forward recursion is used starting * from values of j0(x) and j1(x). * for n>x, a continued fraction approximation to * j(n,x)/j(n-1,x) is evaluated and then backward * recursion is used starting from a supposed value * for j(n,x). The resulting value of j(0,x) is * compared with the actual value to correct the * supposed value of j(n,x). * * yn(n,x) is similar in all respects, except * that forward recursion is used for all * values of n>1. */ use super::{cos, fabs, get_high_word, get_low_word, j0, j1, log, sin, sqrt, y0, y1}; const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ /// Integer 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 jn(n: i32, mut x: f64) -> f64 { let mut ix: u32; let lx: u32; let nm1: i32; let mut i: i32; let mut sign: bool; let mut a: f64; let mut b: f64; let mut temp: f64; ix = get_high_word(x); lx = get_low_word(x); sign = (ix >> 31) != 0; ix &= 0x7fffffff; // -lx == !lx + 1 if ix | ((lx | (!lx).wrapping_add(1)) >> 31) > 0x7ff00000 { /* nan */ return x; } /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x) * Thus, J(-n,x) = J(n,-x) */ /* nm1 = |n|-1 is used instead of |n| to handle n==INT_MIN */ if n == 0 { return j0(x); } if n < 0 { nm1 = -(n + 1); x = -x; sign = !sign; } else { nm1 = n - 1; } if nm1 == 0 { return j1(x); } sign &= (n & 1) != 0; /* even n: 0, odd n: signbit(x) */ x = fabs(x); if (ix | lx) == 0 || ix == 0x7ff00000 { /* if x is 0 or inf */ b = 0.0; } else if (nm1 as f64) < x { /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ if ix >= 0x52d00000 { /* x > 2**302 */ /* (x >> n**2) * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) * Let s=sin(x), c=cos(x), * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then * * n sin(xn)*sqt2 cos(xn)*sqt2 * ---------------------------------- * 0 s-c c+s * 1 -s-c -c+s * 2 -s+c -c-s * 3 s+c c-s */ temp = match nm1 & 3 { 0 => -cos(x) + sin(x), 1 => -cos(x) - sin(x), 2 => cos(x) - sin(x), // 3 _ => cos(x) + sin(x), }; b = INVSQRTPI * temp / sqrt(x); } else { a = j0(x); b = j1(x); i = 0; while i < nm1 { i += 1; temp = b; b = b * (2.0 * (i as f64) / x) - a; /* avoid underflow */ a = temp; } } } else if ix < 0x3e100000 { /* x < 2**-29 */ /* x is tiny, return the first Taylor expansion of J(n,x) * J(n,x) = 1/n!*(x/2)^n - ... */ if nm1 > 32 { /* underflow */ b = 0.0; } else { temp = x * 0.5; b = temp; a = 1.0; i = 2; while i <= nm1 + 1 { a *= i as f64; /* a = n! */ b *= temp; /* b = (x/2)^n */ i += 1; } b = b / a; } } else { /* use backward recurrence */ /* x x^2 x^2 * J(n,x)/J(n-1,x) = ---- ------ ------ ..... * 2n - 2(n+1) - 2(n+2) * * 1 1 1 * (for large x) = ---- ------ ------ ..... * 2n 2(n+1) 2(n+2) * -- - ------ - ------ - * x x x * * Let w = 2n/x and h=2/x, then the above quotient * is equal to the continued fraction: * 1 * = ----------------------- * 1 * w - ----------------- * 1 * w+h - --------- * w+2h - ... * * To determine how many terms needed, let * Q(0) = w, Q(1) = w(w+h) - 1, * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), * When Q(k) > 1e4 good for single * When Q(k) > 1e9 good for double * When Q(k) > 1e17 good for quadruple */ /* determine k */ let mut t: f64; let mut q0: f64; let mut q1: f64; let mut w: f64; let h: f64; let mut z: f64; let mut tmp: f64; let nf: f64; let mut k: i32; nf = (nm1 as f64) + 1.0; w = 2.0 * nf / x; h = 2.0 / x; z = w + h; q0 = w; q1 = w * z - 1.0; k = 1; while q1 < 1.0e9 { k += 1; z += h; tmp = z * q1 - q0; q0 = q1; q1 = tmp; } t = 0.0; i = k; while i >= 0 { t = 1.0 / (2.0 * ((i as f64) + nf) / x - t); i -= 1; } a = t; b = 1.0; /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) * Hence, if n*(log(2n/x)) > ... * single 8.8722839355e+01 * double 7.09782712893383973096e+02 * long double 1.1356523406294143949491931077970765006170e+04 * then recurrent value may overflow and the result is * likely underflow to zero */ tmp = nf * log(fabs(w)); if tmp < 7.09782712893383973096e+02 { i = nm1; while i > 0 { temp = b; b = b * (2.0 * (i as f64)) / x - a; a = temp; i -= 1; } } else { i = nm1; while i > 0 { temp = b; b = b * (2.0 * (i as f64)) / x - a; a = temp; /* scale b to avoid spurious overflow */ let x1p500 = f64::from_bits(0x5f30000000000000); // 0x1p500 == 2^500 if b > x1p500 { a /= b; t /= b; b = 1.0; } i -= 1; } } z = j0(x); w = j1(x); if fabs(z) >= fabs(w) { b = t * z / b; } else { b = t * w / a; } } if sign { -b } else { b } } /// Integer 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 yn(n: i32, x: f64) -> f64 { let mut ix: u32; let lx: u32; let mut ib: u32; let nm1: i32; let mut sign: bool; let mut i: i32; let mut a: f64; let mut b: f64; let mut temp: f64; ix = get_high_word(x); lx = get_low_word(x); sign = (ix >> 31) != 0; ix &= 0x7fffffff; // -lx == !lx + 1 if ix | ((lx | (!lx).wrapping_add(1)) >> 31) > 0x7ff00000 { /* nan */ return x; } if sign && (ix | lx) != 0 { /* x < 0 */ return 0.0 / 0.0; } if ix == 0x7ff00000 { return 0.0; } if n == 0 { return y0(x); } if n < 0 { nm1 = -(n + 1); sign = (n & 1) != 0; } else { nm1 = n - 1; sign = false; } if nm1 == 0 { if sign { return -y1(x); } else { return y1(x); } } if ix >= 0x52d00000 { /* x > 2**302 */ /* (x >> n**2) * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) * Let s=sin(x), c=cos(x), * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then * * n sin(xn)*sqt2 cos(xn)*sqt2 * ---------------------------------- * 0 s-c c+s * 1 -s-c -c+s * 2 -s+c -c-s * 3 s+c c-s */ temp = match nm1 & 3 { 0 => -sin(x) - cos(x), 1 => -sin(x) + cos(x), 2 => sin(x) + cos(x), // 3 _ => sin(x) - cos(x), }; b = INVSQRTPI * temp / sqrt(x); } else { a = y0(x); b = y1(x); /* quit if b is -inf */ ib = get_high_word(b); i = 0; while i < nm1 && ib != 0xfff00000 { i += 1; temp = b; b = (2.0 * (i as f64) / x) * b - a; ib = get_high_word(b); a = temp; } } if sign { -b } else { b } } libm-0.2.15/src/math/jnf.rs000064400000000000000000000151101046102023000134750ustar 00000000000000/* origin: FreeBSD /usr/src/lib/msun/src/e_jnf.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, j0f, j1f, logf, y0f, y1f}; /// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn jnf(n: i32, mut x: f32) -> f32 { let mut ix: u32; let mut nm1: i32; let mut sign: bool; let mut i: i32; let mut a: f32; let mut b: f32; let mut temp: f32; ix = x.to_bits(); sign = (ix >> 31) != 0; ix &= 0x7fffffff; if ix > 0x7f800000 { /* nan */ return x; } /* J(-n,x) = J(n,-x), use |n|-1 to avoid overflow in -n */ if n == 0 { return j0f(x); } if n < 0 { nm1 = -(n + 1); x = -x; sign = !sign; } else { nm1 = n - 1; } if nm1 == 0 { return j1f(x); } sign &= (n & 1) != 0; /* even n: 0, odd n: signbit(x) */ x = fabsf(x); if ix == 0 || ix == 0x7f800000 { /* if x is 0 or inf */ b = 0.0; } else if (nm1 as f32) < x { /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ a = j0f(x); b = j1f(x); i = 0; while i < nm1 { i += 1; temp = b; b = b * (2.0 * (i as f32) / x) - a; a = temp; } } else if ix < 0x35800000 { /* x < 2**-20 */ /* x is tiny, return the first Taylor expansion of J(n,x) * J(n,x) = 1/n!*(x/2)^n - ... */ if nm1 > 8 { /* underflow */ nm1 = 8; } temp = 0.5 * x; b = temp; a = 1.0; i = 2; while i <= nm1 + 1 { a *= i as f32; /* a = n! */ b *= temp; /* b = (x/2)^n */ i += 1; } b = b / a; } else { /* use backward recurrence */ /* x x^2 x^2 * J(n,x)/J(n-1,x) = ---- ------ ------ ..... * 2n - 2(n+1) - 2(n+2) * * 1 1 1 * (for large x) = ---- ------ ------ ..... * 2n 2(n+1) 2(n+2) * -- - ------ - ------ - * x x x * * Let w = 2n/x and h=2/x, then the above quotient * is equal to the continued fraction: * 1 * = ----------------------- * 1 * w - ----------------- * 1 * w+h - --------- * w+2h - ... * * To determine how many terms needed, let * Q(0) = w, Q(1) = w(w+h) - 1, * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), * When Q(k) > 1e4 good for single * When Q(k) > 1e9 good for double * When Q(k) > 1e17 good for quadruple */ /* determine k */ let mut t: f32; let mut q0: f32; let mut q1: f32; let mut w: f32; let h: f32; let mut z: f32; let mut tmp: f32; let nf: f32; let mut k: i32; nf = (nm1 as f32) + 1.0; w = 2.0 * nf / x; h = 2.0 / x; z = w + h; q0 = w; q1 = w * z - 1.0; k = 1; while q1 < 1.0e4 { k += 1; z += h; tmp = z * q1 - q0; q0 = q1; q1 = tmp; } t = 0.0; i = k; while i >= 0 { t = 1.0 / (2.0 * ((i as f32) + nf) / x - t); i -= 1; } a = t; b = 1.0; /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) * Hence, if n*(log(2n/x)) > ... * single 8.8722839355e+01 * double 7.09782712893383973096e+02 * long double 1.1356523406294143949491931077970765006170e+04 * then recurrent value may overflow and the result is * likely underflow to zero */ tmp = nf * logf(fabsf(w)); if tmp < 88.721679688 { i = nm1; while i > 0 { temp = b; b = 2.0 * (i as f32) * b / x - a; a = temp; i -= 1; } } else { i = nm1; while i > 0 { temp = b; b = 2.0 * (i as f32) * b / x - a; a = temp; /* scale b to avoid spurious overflow */ let x1p60 = f32::from_bits(0x5d800000); // 0x1p60 == 2^60 if b > x1p60 { a /= b; t /= b; b = 1.0; } i -= 1; } } z = j0f(x); w = j1f(x); if fabsf(z) >= fabsf(w) { b = t * z / b; } else { b = t * w / a; } } if sign { -b } else { b } } /// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ynf(n: i32, x: f32) -> f32 { let mut ix: u32; let mut ib: u32; let nm1: i32; let mut sign: bool; let mut i: i32; let mut a: f32; let mut b: f32; let mut temp: f32; ix = x.to_bits(); sign = (ix >> 31) != 0; ix &= 0x7fffffff; if ix > 0x7f800000 { /* nan */ return x; } if sign && ix != 0 { /* x < 0 */ return 0.0 / 0.0; } if ix == 0x7f800000 { return 0.0; } if n == 0 { return y0f(x); } if n < 0 { nm1 = -(n + 1); sign = (n & 1) != 0; } else { nm1 = n - 1; sign = false; } if nm1 == 0 { if sign { return -y1f(x); } else { return y1f(x); } } a = y0f(x); b = y1f(x); /* quit if b is -inf */ ib = b.to_bits(); i = 0; while i < nm1 && ib != 0xff800000 { i += 1; temp = b; b = (2.0 * (i as f32) / x) * b - a; ib = b.to_bits(); a = temp; } if sign { -b } else { b } } libm-0.2.15/src/math/k_cos.rs000064400000000000000000000056511046102023000140270ustar 00000000000000// origin: FreeBSD /usr/src/lib/msun/src/k_cos.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. // ==================================================== const C1: f64 = 4.16666666666666019037e-02; /* 0x3FA55555, 0x5555554C */ const C2: f64 = -1.38888888888741095749e-03; /* 0xBF56C16C, 0x16C15177 */ const C3: f64 = 2.48015872894767294178e-05; /* 0x3EFA01A0, 0x19CB1590 */ const C4: f64 = -2.75573143513906633035e-07; /* 0xBE927E4F, 0x809C52AD */ const C5: f64 = 2.08757232129817482790e-09; /* 0x3E21EE9E, 0xBDB4B1C4 */ const C6: f64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ // kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 // Input x is assumed to be bounded by ~pi/4 in magnitude. // Input y is the tail of x. // // Algorithm // 1. Since cos(-x) = cos(x), we need only to consider positive x. // 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0. // 3. cos(x) is approximated by a polynomial of degree 14 on // [0,pi/4] // 4 14 // cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x // where the remez error is // // | 2 4 6 8 10 12 14 | -58 // |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2 // | | // // 4 6 8 10 12 14 // 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then // cos(x) ~ 1 - x*x/2 + r // since cos(x+y) ~ cos(x) - sin(x)*y // ~ cos(x) - x*y, // a correction term is necessary in cos(x) and hence // cos(x+y) = 1 - (x*x/2 - (r - x*y)) // For better accuracy, rearrange to // cos(x+y) ~ w + (tmp + (r-x*y)) // where w = 1 - x*x/2 and tmp is a tiny correction term // (1 - x*x/2 == w + tmp exactly in infinite precision). // The exactness of w + tmp in infinite precision depends on w // and tmp having the same precision as x. If they have extra // precision due to compiler bugs, then the extra precision is // only good provided it is retained in all terms of the final // expression for cos(). Retention happens in all cases tested // under FreeBSD, so don't pessimize things by forcibly clipping // any extra precision in w. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_cos(x: f64, y: f64) -> f64 { let z = x * x; let w = z * z; let r = z * (C1 + z * (C2 + z * C3)) + w * w * (C4 + z * (C5 + z * C6)); let hz = 0.5 * z; let w = 1.0 - hz; w + (((1.0 - w) - hz) + (z * r - x * y)) } libm-0.2.15/src/math/k_cosf.rs000064400000000000000000000021541046102023000141700ustar 00000000000000/* origin: FreeBSD /usr/src/lib/msun/src/k_cosf.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. * ==================================================== */ /* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ const C0: f64 = -0.499999997251031003120; /* -0x1ffffffd0c5e81.0p-54 */ const C1: f64 = 0.0416666233237390631894; /* 0x155553e1053a42.0p-57 */ const C2: f64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ const C3: f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_cosf(x: f64) -> f32 { let z = x * x; let w = z * z; let r = C2 + z * C3; (((1.0 + z * C0) + w * C1) + (w * z) * r) as f32 } libm-0.2.15/src/math/k_expo2.rs000064400000000000000000000010661046102023000142740ustar 00000000000000use super::exp; /* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ const K: i32 = 2043; /* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_expo2(x: f64) -> f64 { let k_ln2 = f64::from_bits(0x40962066151add8b); /* note that k is odd and scale*scale overflows */ let scale = f64::from_bits(((((0x3ff + K / 2) as u32) << 20) as u64) << 32); /* exp(x - k ln2) * 2**(k-1) */ exp(x - k_ln2) * scale * scale } libm-0.2.15/src/math/k_expo2f.rs000064400000000000000000000010361046102023000144370ustar 00000000000000use super::expf; /* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ const K: i32 = 235; /* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_expo2f(x: f32) -> f32 { let k_ln2 = f32::from_bits(0x4322e3bc); /* note that k is odd and scale*scale overflows */ let scale = f32::from_bits(((0x7f + K / 2) as u32) << 23); /* exp(x - k ln2) * 2**(k-1) */ expf(x - k_ln2) * scale * scale } libm-0.2.15/src/math/k_sin.rs000064400000000000000000000046461046102023000140370ustar 00000000000000// origin: FreeBSD /usr/src/lib/msun/src/k_sin.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. // ==================================================== const S1: f64 = -1.66666666666666324348e-01; /* 0xBFC55555, 0x55555549 */ const S2: f64 = 8.33333333332248946124e-03; /* 0x3F811111, 0x1110F8A6 */ const S3: f64 = -1.98412698298579493134e-04; /* 0xBF2A01A0, 0x19C161D5 */ const S4: f64 = 2.75573137070700676789e-06; /* 0x3EC71DE3, 0x57B1FE7D */ const S5: f64 = -2.50507602534068634195e-08; /* 0xBE5AE5E6, 0x8A2B9CEB */ const S6: f64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ // kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 // Input x is assumed to be bounded by ~pi/4 in magnitude. // Input y is the tail of x. // Input iy indicates whether y is 0. (if iy=0, y assume to be 0). // // Algorithm // 1. Since sin(-x) = -sin(x), we need only to consider positive x. // 2. Callers must return sin(-0) = -0 without calling here since our // odd polynomial is not evaluated in a way that preserves -0. // Callers may do the optimization sin(x) ~ x for tiny x. // 3. sin(x) is approximated by a polynomial of degree 13 on // [0,pi/4] // 3 13 // sin(x) ~ x + S1*x + ... + S6*x // where // // |sin(x) 2 4 6 8 10 12 | -58 // |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 // | x | // // 4. sin(x+y) = sin(x) + sin'(x')*y // ~ sin(x) + (1-x*x/2)*y // For better accuracy, let // 3 2 2 2 2 // r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) // then 3 2 // sin(x) = x + (S1*x + (x *(r-y/2)+y)) #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_sin(x: f64, y: f64, iy: i32) -> f64 { let z = x * x; let w = z * z; let r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6); let v = z * x; if iy == 0 { x + v * (S1 + z * r) } else { x - ((z * (0.5 * y - v * r) - y) - v * S1) } } libm-0.2.15/src/math/k_sinf.rs000064400000000000000000000021611046102023000141730ustar 00000000000000/* origin: FreeBSD /usr/src/lib/msun/src/k_sinf.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. * ==================================================== */ /* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ const S1: f64 = -0.166666666416265235595; /* -0x15555554cbac77.0p-55 */ const S2: f64 = 0.0083333293858894631756; /* 0x111110896efbb2.0p-59 */ const S3: f64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ const S4: f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_sinf(x: f64) -> f32 { let z = x * x; let w = z * z; let r = S3 + z * S4; let s = z * x; ((x + s * (S1 + z * S2)) + s * w * r) as f32 } libm-0.2.15/src/math/k_tan.rs000064400000000000000000000102141046102023000140140ustar 00000000000000// origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */ // // ==================================================== // Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. // // Permission to use, copy, modify, and distribute this // software is freely granted, provided that this notice // is preserved. // ==================================================== // kernel tan function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 // Input x is assumed to be bounded by ~pi/4 in magnitude. // Input y is the tail of x. // Input odd indicates whether tan (if odd = 0) or -1/tan (if odd = 1) is returned. // // Algorithm // 1. Since tan(-x) = -tan(x), we need only to consider positive x. // 2. Callers must return tan(-0) = -0 without calling here since our // odd polynomial is not evaluated in a way that preserves -0. // Callers may do the optimization tan(x) ~ x for tiny x. // 3. tan(x) is approximated by a odd polynomial of degree 27 on // [0,0.67434] // 3 27 // tan(x) ~ x + T1*x + ... + T13*x // where // // |tan(x) 2 4 26 | -59.2 // |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2 // | x | // // Note: tan(x+y) = tan(x) + tan'(x)*y // ~ tan(x) + (1+x*x)*y // Therefore, for better accuracy in computing tan(x+y), let // 3 2 2 2 2 // r = x *(T2+x *(T3+x *(...+x *(T12+x *T13)))) // then // 3 2 // tan(x+y) = x + (T1*x + (x *(r+y)+y)) // // 4. For x in [0.67434,pi/4], let y = pi/4 - x, then // tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y)) // = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y))) static T: [f64; 13] = [ 3.33333333333334091986e-01, /* 3FD55555, 55555563 */ 1.33333333333201242699e-01, /* 3FC11111, 1110FE7A */ 5.39682539762260521377e-02, /* 3FABA1BA, 1BB341FE */ 2.18694882948595424599e-02, /* 3F9664F4, 8406D637 */ 8.86323982359930005737e-03, /* 3F8226E3, E96E8493 */ 3.59207910759131235356e-03, /* 3F6D6D22, C9560328 */ 1.45620945432529025516e-03, /* 3F57DBC8, FEE08315 */ 5.88041240820264096874e-04, /* 3F4344D8, F2F26501 */ 2.46463134818469906812e-04, /* 3F3026F7, 1A8D1068 */ 7.81794442939557092300e-05, /* 3F147E88, A03792A6 */ 7.14072491382608190305e-05, /* 3F12B80F, 32F0A7E9 */ -1.85586374855275456654e-05, /* BEF375CB, DB605373 */ 2.59073051863633712884e-05, /* 3EFB2A70, 74BF7AD4 */ ]; const PIO4: f64 = 7.85398163397448278999e-01; /* 3FE921FB, 54442D18 */ const PIO4_LO: f64 = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 { let hx = (f64::to_bits(x) >> 32) as u32; let big = (hx & 0x7fffffff) >= 0x3FE59428; /* |x| >= 0.6744 */ if big { let sign = hx >> 31; if sign != 0 { x = -x; y = -y; } x = (PIO4 - x) + (PIO4_LO - y); y = 0.0; } let z = x * x; let w = z * z; /* * Break x^5*(T[1]+x^2*T[2]+...) into * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) + * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12])) */ let r = T[1] + w * (T[3] + w * (T[5] + w * (T[7] + w * (T[9] + w * T[11])))); let v = z * (T[2] + w * (T[4] + w * (T[6] + w * (T[8] + w * (T[10] + w * T[12]))))); let s = z * x; let r = y + z * (s * (r + v) + y) + s * T[0]; let w = x + r; if big { let sign = hx >> 31; let s = 1.0 - 2.0 * odd as f64; let v = s - 2.0 * (x + (r - w * w / (w + s))); return if sign != 0 { -v } else { v }; } if odd == 0 { return w; } /* -1.0/(x+r) has up to 2ulp error, so compute it accurately */ let w0 = zero_low_word(w); let v = r - (w0 - x); /* w0+v = r+x */ let a = -1.0 / w; let a0 = zero_low_word(a); a0 + a * (1.0 + a0 * w0 + a0 * v) } fn zero_low_word(x: f64) -> f64 { f64::from_bits(f64::to_bits(x) & 0xFFFF_FFFF_0000_0000) } libm-0.2.15/src/math/k_tanf.rs000064400000000000000000000036041046102023000141670ustar 00000000000000/* origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */ /* * ==================================================== * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. * * Permission to use, copy, modify, and distribute this * software is freely granted, provided that this notice * is preserved. * ==================================================== */ /* |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). */ const T: [f64; 6] = [ 0.333331395030791399758, /* 0x15554d3418c99f.0p-54 */ 0.133392002712976742718, /* 0x1112fd38999f72.0p-55 */ 0.0533812378445670393523, /* 0x1b54c91d865afe.0p-57 */ 0.0245283181166547278873, /* 0x191df3908c33ce.0p-58 */ 0.00297435743359967304927, /* 0x185dadfcecf44e.0p-61 */ 0.00946564784943673166728, /* 0x1362b9bf971bcd.0p-59 */ ]; #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_tanf(x: f64, odd: bool) -> f32 { let z = x * x; /* * Split up the polynomial into small independent terms to give * opportunities for parallel evaluation. The chosen splitting is * micro-optimized for Athlons (XP, X64). It costs 2 multiplications * relative to Horner's method on sequential machines. * * We add the small terms from lowest degree up for efficiency on * non-sequential machines (the lowest degree terms tend to be ready * earlier). Apart from this, we don't care about order of * operations, and don't need to to care since we have precision to * spare. However, the chosen splitting is good for accuracy too, * and would give results as accurate as Horner's method if the * small terms were added from highest degree down. */ let mut r = T[4] + z * T[5]; let t = T[2] + z * T[3]; let w = z * z; let s = z * x; let u = T[0] + z * T[1]; r = (x + s * u) + (s * w) * (t + w * r); (if odd { -1. / r } else { r }) as f32 } libm-0.2.15/src/math/ldexp.rs000064400000000000000000000010561046102023000140400ustar 00000000000000#[cfg(f16_enabled)] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ldexpf16(x: f16, n: i32) -> f16 { super::scalbnf16(x, n) } #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ldexpf(x: f32, n: i32) -> f32 { super::scalbnf(x, n) } #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ldexp(x: f64, n: i32) -> f64 { super::scalbn(x, n) } #[cfg(f128_enabled)] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ldexpf128(x: f128, n: i32) -> f128 { super::scalbnf128(x, n) } libm-0.2.15/src/math/ldexpf.rs000064400000000000000000000001761046102023000142100ustar 00000000000000#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ldexpf(x: f32, n: i32) -> f32 { super::scalbnf(x, n) } libm-0.2.15/src/math/ldexpf128.rs000064400000000000000000000002061046102023000144350ustar 00000000000000#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ldexpf128(x: f128, n: i32) -> f128 { super::scalbnf128(x, n) } libm-0.2.15/src/math/ldexpf16.rs000064400000000000000000000002021046102023000143450ustar 00000000000000#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ldexpf16(x: f16, n: i32) -> f16 { super::scalbnf16(x, n) } libm-0.2.15/src/math/lgamma.rs000064400000000000000000000003601046102023000141570ustar 00000000000000use super::lgamma_r; /// The natural logarithm of the /// [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn lgamma(x: f64) -> f64 { lgamma_r(x).0 } libm-0.2.15/src/math/lgamma_r.rs000064400000000000000000000306541046102023000145110ustar 00000000000000/* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.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. * ==================================================== * */ /* lgamma_r(x, signgamp) * Reentrant version of the logarithm of the Gamma function * with user provide pointer for the sign of Gamma(x). * * Method: * 1. Argument Reduction for 0 < x <= 8 * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may * reduce x to a number in [1.5,2.5] by * lgamma(1+s) = log(s) + lgamma(s) * for example, * lgamma(7.3) = log(6.3) + lgamma(6.3) * = log(6.3*5.3) + lgamma(5.3) * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) * 2. Polynomial approximation of lgamma around its * minimun ymin=1.461632144968362245 to maintain monotonicity. * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use * Let z = x-ymin; * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) * where * poly(z) is a 14 degree polynomial. * 2. Rational approximation in the primary interval [2,3] * We use the following approximation: * s = x-2.0; * lgamma(x) = 0.5*s + s*P(s)/Q(s) * with accuracy * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71 * Our algorithms are based on the following observation * * zeta(2)-1 2 zeta(3)-1 3 * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... * 2 3 * * where Euler = 0.5771... is the Euler constant, which is very * close to 0.5. * * 3. For x>=8, we have * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... * (better formula: * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) * Let z = 1/x, then we approximation * f(z) = lgamma(x) - (x-0.5)(log(x)-1) * by * 3 5 11 * w = w0 + w1*z + w2*z + w3*z + ... + w6*z * where * |w - f(z)| < 2**-58.74 * * 4. For negative x, since (G is gamma function) * -x*G(-x)*G(x) = PI/sin(PI*x), * we have * G(x) = PI/(sin(PI*x)*(-x)*G(-x)) * since G(-x) is positive, sign(G(x)) = sign(sin(PI*x)) for x<0 * Hence, for x<0, signgam = sign(sin(PI*x)) and * lgamma(x) = log(|Gamma(x)|) * = log(PI/(|x*sin(PI*x)|)) - lgamma(-x); * Note: one should avoid compute PI*(-x) directly in the * computation of sin(PI*(-x)). * * 5. Special Cases * lgamma(2+s) ~ s*(1-Euler) for tiny s * lgamma(1) = lgamma(2) = 0 * lgamma(x) ~ -log(|x|) for tiny x * lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero * lgamma(inf) = inf * lgamma(-inf) = inf (bug for bug compatible with C99!?) * */ use super::{floor, k_cos, k_sin, log}; const PI: f64 = 3.14159265358979311600e+00; /* 0x400921FB, 0x54442D18 */ const A0: f64 = 7.72156649015328655494e-02; /* 0x3FB3C467, 0xE37DB0C8 */ const A1: f64 = 3.22467033424113591611e-01; /* 0x3FD4A34C, 0xC4A60FAD */ const A2: f64 = 6.73523010531292681824e-02; /* 0x3FB13E00, 0x1A5562A7 */ const A3: f64 = 2.05808084325167332806e-02; /* 0x3F951322, 0xAC92547B */ const A4: f64 = 7.38555086081402883957e-03; /* 0x3F7E404F, 0xB68FEFE8 */ const A5: f64 = 2.89051383673415629091e-03; /* 0x3F67ADD8, 0xCCB7926B */ const A6: f64 = 1.19270763183362067845e-03; /* 0x3F538A94, 0x116F3F5D */ const A7: f64 = 5.10069792153511336608e-04; /* 0x3F40B6C6, 0x89B99C00 */ const A8: f64 = 2.20862790713908385557e-04; /* 0x3F2CF2EC, 0xED10E54D */ const A9: f64 = 1.08011567247583939954e-04; /* 0x3F1C5088, 0x987DFB07 */ const A10: f64 = 2.52144565451257326939e-05; /* 0x3EFA7074, 0x428CFA52 */ const A11: f64 = 4.48640949618915160150e-05; /* 0x3F07858E, 0x90A45837 */ const TC: f64 = 1.46163214496836224576e+00; /* 0x3FF762D8, 0x6356BE3F */ const TF: f64 = -1.21486290535849611461e-01; /* 0xBFBF19B9, 0xBCC38A42 */ /* tt = -(tail of TF) */ const TT: f64 = -3.63867699703950536541e-18; /* 0xBC50C7CA, 0xA48A971F */ const T0: f64 = 4.83836122723810047042e-01; /* 0x3FDEF72B, 0xC8EE38A2 */ const T1: f64 = -1.47587722994593911752e-01; /* 0xBFC2E427, 0x8DC6C509 */ const T2: f64 = 6.46249402391333854778e-02; /* 0x3FB08B42, 0x94D5419B */ const T3: f64 = -3.27885410759859649565e-02; /* 0xBFA0C9A8, 0xDF35B713 */ const T4: f64 = 1.79706750811820387126e-02; /* 0x3F9266E7, 0x970AF9EC */ const T5: f64 = -1.03142241298341437450e-02; /* 0xBF851F9F, 0xBA91EC6A */ const T6: f64 = 6.10053870246291332635e-03; /* 0x3F78FCE0, 0xE370E344 */ const T7: f64 = -3.68452016781138256760e-03; /* 0xBF6E2EFF, 0xB3E914D7 */ const T8: f64 = 2.25964780900612472250e-03; /* 0x3F6282D3, 0x2E15C915 */ const T9: f64 = -1.40346469989232843813e-03; /* 0xBF56FE8E, 0xBF2D1AF1 */ const T10: f64 = 8.81081882437654011382e-04; /* 0x3F4CDF0C, 0xEF61A8E9 */ const T11: f64 = -5.38595305356740546715e-04; /* 0xBF41A610, 0x9C73E0EC */ const T12: f64 = 3.15632070903625950361e-04; /* 0x3F34AF6D, 0x6C0EBBF7 */ const T13: f64 = -3.12754168375120860518e-04; /* 0xBF347F24, 0xECC38C38 */ const T14: f64 = 3.35529192635519073543e-04; /* 0x3F35FD3E, 0xE8C2D3F4 */ const U0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ const U1: f64 = 6.32827064025093366517e-01; /* 0x3FE4401E, 0x8B005DFF */ const U2: f64 = 1.45492250137234768737e+00; /* 0x3FF7475C, 0xD119BD6F */ const U3: f64 = 9.77717527963372745603e-01; /* 0x3FEF4976, 0x44EA8450 */ const U4: f64 = 2.28963728064692451092e-01; /* 0x3FCD4EAE, 0xF6010924 */ const U5: f64 = 1.33810918536787660377e-02; /* 0x3F8B678B, 0xBF2BAB09 */ const V1: f64 = 2.45597793713041134822e+00; /* 0x4003A5D7, 0xC2BD619C */ const V2: f64 = 2.12848976379893395361e+00; /* 0x40010725, 0xA42B18F5 */ const V3: f64 = 7.69285150456672783825e-01; /* 0x3FE89DFB, 0xE45050AF */ const V4: f64 = 1.04222645593369134254e-01; /* 0x3FBAAE55, 0xD6537C88 */ const V5: f64 = 3.21709242282423911810e-03; /* 0x3F6A5ABB, 0x57D0CF61 */ const S0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ const S1: f64 = 2.14982415960608852501e-01; /* 0x3FCB848B, 0x36E20878 */ const S2: f64 = 3.25778796408930981787e-01; /* 0x3FD4D98F, 0x4F139F59 */ const S3: f64 = 1.46350472652464452805e-01; /* 0x3FC2BB9C, 0xBEE5F2F7 */ const S4: f64 = 2.66422703033638609560e-02; /* 0x3F9B481C, 0x7E939961 */ const S5: f64 = 1.84028451407337715652e-03; /* 0x3F5E26B6, 0x7368F239 */ const S6: f64 = 3.19475326584100867617e-05; /* 0x3F00BFEC, 0xDD17E945 */ const R1: f64 = 1.39200533467621045958e+00; /* 0x3FF645A7, 0x62C4AB74 */ const R2: f64 = 7.21935547567138069525e-01; /* 0x3FE71A18, 0x93D3DCDC */ const R3: f64 = 1.71933865632803078993e-01; /* 0x3FC601ED, 0xCCFBDF27 */ const R4: f64 = 1.86459191715652901344e-02; /* 0x3F9317EA, 0x742ED475 */ const R5: f64 = 7.77942496381893596434e-04; /* 0x3F497DDA, 0xCA41A95B */ const R6: f64 = 7.32668430744625636189e-06; /* 0x3EDEBAF7, 0xA5B38140 */ const W0: f64 = 4.18938533204672725052e-01; /* 0x3FDACFE3, 0x90C97D69 */ const W1: f64 = 8.33333333333329678849e-02; /* 0x3FB55555, 0x5555553B */ const W2: f64 = -2.77777777728775536470e-03; /* 0xBF66C16C, 0x16B02E5C */ const W3: f64 = 7.93650558643019558500e-04; /* 0x3F4A019F, 0x98CF38B6 */ const W4: f64 = -5.95187557450339963135e-04; /* 0xBF4380CB, 0x8C0FE741 */ const W5: f64 = 8.36339918996282139126e-04; /* 0x3F4B67BA, 0x4CDAD5D1 */ const W6: f64 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ /* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ fn sin_pi(mut x: f64) -> f64 { let mut n: i32; /* spurious inexact if odd int */ x = 2.0 * (x * 0.5 - floor(x * 0.5)); /* x mod 2.0 */ n = (x * 4.0) as i32; n = div!(n + 1, 2); x -= (n as f64) * 0.5; x *= PI; match n { 1 => k_cos(x, 0.0), 2 => k_sin(-x, 0.0, 0), 3 => -k_cos(x, 0.0), // 0 _ => k_sin(x, 0.0, 0), } } #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn lgamma_r(mut x: f64) -> (f64, i32) { let u: u64 = x.to_bits(); let mut t: f64; let y: f64; let mut z: f64; let nadj: f64; let p: f64; let p1: f64; let p2: f64; let p3: f64; let q: f64; let mut r: f64; let w: f64; let ix: u32; let sign: bool; let i: i32; let mut signgam: i32; /* purge off +-inf, NaN, +-0, tiny and negative arguments */ signgam = 1; sign = (u >> 63) != 0; ix = ((u >> 32) as u32) & 0x7fffffff; if ix >= 0x7ff00000 { return (x * x, signgam); } if ix < (0x3ff - 70) << 20 { /* |x|<2**-70, return -log(|x|) */ if sign { x = -x; signgam = -1; } return (-log(x), signgam); } if sign { x = -x; t = sin_pi(x); if t == 0.0 { /* -integer */ return (1.0 / (x - x), signgam); } if t > 0.0 { signgam = -1; } else { t = -t; } nadj = log(PI / (t * x)); } else { nadj = 0.0; } /* purge off 1 and 2 */ if (ix == 0x3ff00000 || ix == 0x40000000) && (u & 0xffffffff) == 0 { r = 0.0; } /* for x < 2.0 */ else if ix < 0x40000000 { if ix <= 0x3feccccc { /* lgamma(x) = lgamma(x+1)-log(x) */ r = -log(x); if ix >= 0x3FE76944 { y = 1.0 - x; i = 0; } else if ix >= 0x3FCDA661 { y = x - (TC - 1.0); i = 1; } else { y = x; i = 2; } } else { r = 0.0; if ix >= 0x3FFBB4C3 { /* [1.7316,2] */ y = 2.0 - x; i = 0; } else if ix >= 0x3FF3B4C4 { /* [1.23,1.73] */ y = x - TC; i = 1; } else { y = x - 1.0; i = 2; } } match i { 0 => { z = y * y; p1 = A0 + z * (A2 + z * (A4 + z * (A6 + z * (A8 + z * A10)))); p2 = z * (A1 + z * (A3 + z * (A5 + z * (A7 + z * (A9 + z * A11))))); p = y * p1 + p2; r += p - 0.5 * y; } 1 => { z = y * y; w = z * y; p1 = T0 + w * (T3 + w * (T6 + w * (T9 + w * T12))); /* parallel comp */ p2 = T1 + w * (T4 + w * (T7 + w * (T10 + w * T13))); p3 = T2 + w * (T5 + w * (T8 + w * (T11 + w * T14))); p = z * p1 - (TT - w * (p2 + y * p3)); r += TF + p; } 2 => { p1 = y * (U0 + y * (U1 + y * (U2 + y * (U3 + y * (U4 + y * U5))))); p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); r += -0.5 * y + p1 / p2; } #[cfg(debug_assertions)] _ => unreachable!(), #[cfg(not(debug_assertions))] _ => {} } } else if ix < 0x40200000 { /* x < 8.0 */ i = x as i32; y = x - (i as f64); p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); r = 0.5 * y + p / q; z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ // TODO: In C, this was implemented using switch jumps with fallthrough. // Does this implementation have performance problems? if i >= 7 { z *= y + 6.0; } if i >= 6 { z *= y + 5.0; } if i >= 5 { z *= y + 4.0; } if i >= 4 { z *= y + 3.0; } if i >= 3 { z *= y + 2.0; r += log(z); } } else if ix < 0x43900000 { /* 8.0 <= x < 2**58 */ t = log(x); z = 1.0 / x; y = z * z; w = W0 + z * (W1 + y * (W2 + y * (W3 + y * (W4 + y * (W5 + y * W6))))); r = (x - 0.5) * (t - 1.0) + w; } else { /* 2**58 <= x <= inf */ r = x * (log(x) - 1.0); } if sign { r = nadj - r; } return (r, signgam); } libm-0.2.15/src/math/lgammaf.rs000064400000000000000000000003631046102023000143300ustar 00000000000000use super::lgammaf_r; /// The natural logarithm of the /// [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn lgammaf(x: f32) -> f32 { lgammaf_r(x).0 } libm-0.2.15/src/math/lgammaf_r.rs000064400000000000000000000206061046102023000146530ustar 00000000000000/* origin: FreeBSD /usr/src/lib/msun/src/e_lgammaf_r.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::{floorf, k_cosf, k_sinf, logf}; const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ const A0: f32 = 7.7215664089e-02; /* 0x3d9e233f */ const A1: f32 = 3.2246702909e-01; /* 0x3ea51a66 */ const A2: f32 = 6.7352302372e-02; /* 0x3d89f001 */ const A3: f32 = 2.0580807701e-02; /* 0x3ca89915 */ const A4: f32 = 7.3855509982e-03; /* 0x3bf2027e */ const A5: f32 = 2.8905137442e-03; /* 0x3b3d6ec6 */ const A6: f32 = 1.1927076848e-03; /* 0x3a9c54a1 */ const A7: f32 = 5.1006977446e-04; /* 0x3a05b634 */ const A8: f32 = 2.2086278477e-04; /* 0x39679767 */ const A9: f32 = 1.0801156895e-04; /* 0x38e28445 */ const A10: f32 = 2.5214456400e-05; /* 0x37d383a2 */ const A11: f32 = 4.4864096708e-05; /* 0x383c2c75 */ const TC: f32 = 1.4616321325e+00; /* 0x3fbb16c3 */ const TF: f32 = -1.2148628384e-01; /* 0xbdf8cdcd */ /* TT = -(tail of TF) */ const TT: f32 = 6.6971006518e-09; /* 0x31e61c52 */ const T0: f32 = 4.8383611441e-01; /* 0x3ef7b95e */ const T1: f32 = -1.4758771658e-01; /* 0xbe17213c */ const T2: f32 = 6.4624942839e-02; /* 0x3d845a15 */ const T3: f32 = -3.2788541168e-02; /* 0xbd064d47 */ const T4: f32 = 1.7970675603e-02; /* 0x3c93373d */ const T5: f32 = -1.0314224288e-02; /* 0xbc28fcfe */ const T6: f32 = 6.1005386524e-03; /* 0x3bc7e707 */ const T7: f32 = -3.6845202558e-03; /* 0xbb7177fe */ const T8: f32 = 2.2596477065e-03; /* 0x3b141699 */ const T9: f32 = -1.4034647029e-03; /* 0xbab7f476 */ const T10: f32 = 8.8108185446e-04; /* 0x3a66f867 */ const T11: f32 = -5.3859531181e-04; /* 0xba0d3085 */ const T12: f32 = 3.1563205994e-04; /* 0x39a57b6b */ const T13: f32 = -3.1275415677e-04; /* 0xb9a3f927 */ const T14: f32 = 3.3552918467e-04; /* 0x39afe9f7 */ const U0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ const U1: f32 = 6.3282704353e-01; /* 0x3f2200f4 */ const U2: f32 = 1.4549225569e+00; /* 0x3fba3ae7 */ const U3: f32 = 9.7771751881e-01; /* 0x3f7a4bb2 */ const U4: f32 = 2.2896373272e-01; /* 0x3e6a7578 */ const U5: f32 = 1.3381091878e-02; /* 0x3c5b3c5e */ const V1: f32 = 2.4559779167e+00; /* 0x401d2ebe */ const V2: f32 = 2.1284897327e+00; /* 0x4008392d */ const V3: f32 = 7.6928514242e-01; /* 0x3f44efdf */ const V4: f32 = 1.0422264785e-01; /* 0x3dd572af */ const V5: f32 = 3.2170924824e-03; /* 0x3b52d5db */ const S0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ const S1: f32 = 2.1498242021e-01; /* 0x3e5c245a */ const S2: f32 = 3.2577878237e-01; /* 0x3ea6cc7a */ const S3: f32 = 1.4635047317e-01; /* 0x3e15dce6 */ const S4: f32 = 2.6642270386e-02; /* 0x3cda40e4 */ const S5: f32 = 1.8402845599e-03; /* 0x3af135b4 */ const S6: f32 = 3.1947532989e-05; /* 0x3805ff67 */ const R1: f32 = 1.3920053244e+00; /* 0x3fb22d3b */ const R2: f32 = 7.2193557024e-01; /* 0x3f38d0c5 */ const R3: f32 = 1.7193385959e-01; /* 0x3e300f6e */ const R4: f32 = 1.8645919859e-02; /* 0x3c98bf54 */ const R5: f32 = 7.7794247773e-04; /* 0x3a4beed6 */ const R6: f32 = 7.3266842264e-06; /* 0x36f5d7bd */ const W0: f32 = 4.1893854737e-01; /* 0x3ed67f1d */ const W1: f32 = 8.3333335817e-02; /* 0x3daaaaab */ const W2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ const W3: f32 = 7.9365057172e-04; /* 0x3a500cfd */ const W4: f32 = -5.9518753551e-04; /* 0xba1c065c */ const W5: f32 = 8.3633989561e-04; /* 0x3a5b3dd2 */ const W6: f32 = -1.6309292987e-03; /* 0xbad5c4e8 */ /* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ fn sin_pi(mut x: f32) -> f32 { let mut y: f64; let mut n: isize; /* spurious inexact if odd int */ x = 2.0 * (x * 0.5 - floorf(x * 0.5)); /* x mod 2.0 */ n = (x * 4.0) as isize; n = div!(n + 1, 2); y = (x as f64) - (n as f64) * 0.5; y *= 3.14159265358979323846; match n { 1 => k_cosf(y), 2 => k_sinf(-y), 3 => -k_cosf(y), // 0 _ => k_sinf(y), } } #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn lgammaf_r(mut x: f32) -> (f32, i32) { let u = x.to_bits(); let mut t: f32; let y: f32; let mut z: f32; let nadj: f32; let p: f32; let p1: f32; let p2: f32; let p3: f32; let q: f32; let mut r: f32; let w: f32; let ix: u32; let i: i32; let sign: bool; let mut signgam: i32; /* purge off +-inf, NaN, +-0, tiny and negative arguments */ signgam = 1; sign = (u >> 31) != 0; ix = u & 0x7fffffff; if ix >= 0x7f800000 { return (x * x, signgam); } if ix < 0x35000000 { /* |x| < 2**-21, return -log(|x|) */ if sign { signgam = -1; x = -x; } return (-logf(x), signgam); } if sign { x = -x; t = sin_pi(x); if t == 0.0 { /* -integer */ return (1.0 / (x - x), signgam); } if t > 0.0 { signgam = -1; } else { t = -t; } nadj = logf(PI / (t * x)); } else { nadj = 0.0; } /* purge off 1 and 2 */ if ix == 0x3f800000 || ix == 0x40000000 { r = 0.0; } /* for x < 2.0 */ else if ix < 0x40000000 { if ix <= 0x3f666666 { /* lgamma(x) = lgamma(x+1)-log(x) */ r = -logf(x); if ix >= 0x3f3b4a20 { y = 1.0 - x; i = 0; } else if ix >= 0x3e6d3308 { y = x - (TC - 1.0); i = 1; } else { y = x; i = 2; } } else { r = 0.0; if ix >= 0x3fdda618 { /* [1.7316,2] */ y = 2.0 - x; i = 0; } else if ix >= 0x3F9da620 { /* [1.23,1.73] */ y = x - TC; i = 1; } else { y = x - 1.0; i = 2; } } match i { 0 => { z = y * y; p1 = A0 + z * (A2 + z * (A4 + z * (A6 + z * (A8 + z * A10)))); p2 = z * (A1 + z * (A3 + z * (A5 + z * (A7 + z * (A9 + z * A11))))); p = y * p1 + p2; r += p - 0.5 * y; } 1 => { z = y * y; w = z * y; p1 = T0 + w * (T3 + w * (T6 + w * (T9 + w * T12))); /* parallel comp */ p2 = T1 + w * (T4 + w * (T7 + w * (T10 + w * T13))); p3 = T2 + w * (T5 + w * (T8 + w * (T11 + w * T14))); p = z * p1 - (TT - w * (p2 + y * p3)); r += TF + p; } 2 => { p1 = y * (U0 + y * (U1 + y * (U2 + y * (U3 + y * (U4 + y * U5))))); p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); r += -0.5 * y + p1 / p2; } #[cfg(debug_assertions)] _ => unreachable!(), #[cfg(not(debug_assertions))] _ => {} } } else if ix < 0x41000000 { /* x < 8.0 */ i = x as i32; y = x - (i as f32); p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); r = 0.5 * y + p / q; z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ // TODO: In C, this was implemented using switch jumps with fallthrough. // Does this implementation have performance problems? if i >= 7 { z *= y + 6.0; } if i >= 6 { z *= y + 5.0; } if i >= 5 { z *= y + 4.0; } if i >= 4 { z *= y + 3.0; } if i >= 3 { z *= y + 2.0; r += logf(z); } } else if ix < 0x5c800000 { /* 8.0 <= x < 2**58 */ t = logf(x); z = 1.0 / x; y = z * z; w = W0 + z * (W1 + y * (W2 + y * (W3 + y * (W4 + y * (W5 + y * W6))))); r = (x - 0.5) * (t - 1.0) + w; } else { /* 2**58 <= x <= inf */ r = x * (logf(x) - 1.0); } if sign { r = nadj - r; } return (r, signgam); } libm-0.2.15/src/math/log.rs000064400000000000000000000107601046102023000135070ustar 00000000000000/* origin: FreeBSD /usr/src/lib/msun/src/e_log.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. * ==================================================== */ /* log(x) * Return the logarithm of x * * Method : * 1. Argument Reduction: find k and f such that * x = 2^k * (1+f), * where sqrt(2)/2 < 1+f < sqrt(2) . * * 2. Approximation of log(1+f). * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) * = 2s + 2/3 s**3 + 2/5 s**5 + ....., * = 2s + s*R * We use a special Remez algorithm on [0,0.1716] to generate * a polynomial of degree 14 to approximate R The maximum error * of this polynomial approximation is bounded by 2**-58.45. In * other words, * 2 4 6 8 10 12 14 * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s * (the values of Lg1 to Lg7 are listed in the program) * and * | 2 14 | -58.45 * | Lg1*s +...+Lg7*s - R(z) | <= 2 * | | * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. * In order to guarantee error in log below 1ulp, we compute log * by * log(1+f) = f - s*(f - R) (if f is not too large) * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy) * * 3. Finally, log(x) = k*ln2 + log(1+f). * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) * Here ln2 is split into two floating point number: * ln2_hi + ln2_lo, * where n*ln2_hi is always exact for |n| < 2000. * * Special cases: * log(x) is NaN with signal if x < 0 (including -INF) ; * log(+INF) is +INF; log(0) is -INF with signal; * log(NaN) is that NaN with no signal. * * Accuracy: * according to an error analysis, the error is always less than * 1 ulp (unit in the last place). * * 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. */ const LN2_HI: f64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ const LN2_LO: f64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ /// The natural logarithm of `x` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log(mut x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 let mut ui = x.to_bits(); let mut hx: u32 = (ui >> 32) as u32; let mut k: i32 = 0; if (hx < 0x00100000) || ((hx >> 31) != 0) { /* x < 2**-126 */ if ui << 1 == 0 { return -1. / (x * x); /* log(+-0)=-inf */ } if hx >> 31 != 0 { return (x - x) / 0.0; /* log(-#) = NaN */ } /* subnormal number, scale x up */ k -= 54; x *= x1p54; ui = x.to_bits(); hx = (ui >> 32) as u32; } else if hx >= 0x7ff00000 { return x; } else if hx == 0x3ff00000 && ui << 32 == 0 { return 0.; } /* reduce x into [sqrt(2)/2, sqrt(2)] */ hx += 0x3ff00000 - 0x3fe6a09e; k += ((hx >> 20) as i32) - 0x3ff; hx = (hx & 0x000fffff) + 0x3fe6a09e; ui = ((hx as u64) << 32) | (ui & 0xffffffff); x = f64::from_bits(ui); let f: f64 = x - 1.0; let hfsq: f64 = 0.5 * f * f; let s: f64 = f / (2.0 + f); let z: f64 = s * s; let w: f64 = z * z; let t1: f64 = w * (LG2 + w * (LG4 + w * LG6)); let t2: f64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); let r: f64 = t2 + t1; let dk: f64 = k as f64; s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI } libm-0.2.15/src/math/log10.rs000064400000000000000000000073411046102023000136510ustar 00000000000000/* origin: FreeBSD /usr/src/lib/msun/src/e_log10.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. * ==================================================== */ /* * Return the base 10 logarithm of x. See log.c for most comments. * * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 * as in log.c, then combine and scale in extra precision: * log10(x) = (f - f*f/2 + r)/log(10) + k*log10(2) */ use core::f64; const IVLN10HI: f64 = 4.34294481878168880939e-01; /* 0x3fdbcb7b, 0x15200000 */ const IVLN10LO: f64 = 2.50829467116452752298e-11; /* 0x3dbb9438, 0xca9aadd5 */ const LOG10_2HI: f64 = 3.01029995663611771306e-01; /* 0x3FD34413, 0x509F6000 */ const LOG10_2LO: f64 = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */ const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ /// The base 10 logarithm of `x` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log10(mut x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 let mut ui: u64 = x.to_bits(); let hfsq: f64; let f: f64; let s: f64; let z: f64; let r: f64; let mut w: f64; let t1: f64; let t2: f64; let dk: f64; let y: f64; let mut hi: f64; let lo: f64; let mut val_hi: f64; let mut val_lo: f64; let mut hx: u32; let mut k: i32; hx = (ui >> 32) as u32; k = 0; if hx < 0x00100000 || (hx >> 31) > 0 { if ui << 1 == 0 { return -1. / (x * x); /* log(+-0)=-inf */ } if (hx >> 31) > 0 { return (x - x) / 0.0; /* log(-#) = NaN */ } /* subnormal number, scale x up */ k -= 54; x *= x1p54; ui = x.to_bits(); hx = (ui >> 32) as u32; } else if hx >= 0x7ff00000 { return x; } else if hx == 0x3ff00000 && ui << 32 == 0 { return 0.; } /* reduce x into [sqrt(2)/2, sqrt(2)] */ hx += 0x3ff00000 - 0x3fe6a09e; k += (hx >> 20) as i32 - 0x3ff; hx = (hx & 0x000fffff) + 0x3fe6a09e; ui = ((hx as u64) << 32) | (ui & 0xffffffff); x = f64::from_bits(ui); f = x - 1.0; hfsq = 0.5 * f * f; s = f / (2.0 + f); z = s * s; w = z * z; t1 = w * (LG2 + w * (LG4 + w * LG6)); t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); r = t2 + t1; /* See log2.c for details. */ /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ hi = f - hfsq; ui = hi.to_bits(); ui &= (-1i64 as u64) << 32; hi = f64::from_bits(ui); lo = f - hi - hfsq + s * (hfsq + r); /* val_hi+val_lo ~ log10(1+f) + k*log10(2) */ val_hi = hi * IVLN10HI; dk = k as f64; y = dk * LOG10_2HI; val_lo = dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI; /* * Extra precision in for adding y is not strictly needed * since there is no very large cancellation near x = sqrt(2) or * x = 1/sqrt(2), but we do it anyway since it costs little on CPUs * with some parallelism and it reduces the error for many args. */ w = y + val_hi; val_lo += (y - w) + val_hi; val_hi = w; val_lo + val_hi } libm-0.2.15/src/math/log10f.rs000064400000000000000000000050511046102023000140130ustar 00000000000000/* origin: FreeBSD /usr/src/lib/msun/src/e_log10f.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. * ==================================================== */ /* * See comments in log10.c. */ use core::f32; const IVLN10HI: f32 = 4.3432617188e-01; /* 0x3ede6000 */ const IVLN10LO: f32 = -3.1689971365e-05; /* 0xb804ead9 */ const LOG10_2HI: f32 = 3.0102920532e-01; /* 0x3e9a2080 */ const LOG10_2LO: f32 = 7.9034151668e-07; /* 0x355427db */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ /// The base 10 logarithm of `x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log10f(mut x: f32) -> f32 { let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 let mut ui: u32 = x.to_bits(); let hfsq: f32; let f: f32; let s: f32; let z: f32; let r: f32; let w: f32; let t1: f32; let t2: f32; let dk: f32; let mut hi: f32; let lo: f32; let mut ix: u32; let mut k: i32; ix = ui; k = 0; if ix < 0x00800000 || (ix >> 31) > 0 { /* x < 2**-126 */ if ix << 1 == 0 { return -1. / (x * x); /* log(+-0)=-inf */ } if (ix >> 31) > 0 { return (x - x) / 0.0; /* log(-#) = NaN */ } /* subnormal number, scale up x */ k -= 25; x *= x1p25f; ui = x.to_bits(); ix = ui; } else if ix >= 0x7f800000 { return x; } else if ix == 0x3f800000 { return 0.; } /* reduce x into [sqrt(2)/2, sqrt(2)] */ ix += 0x3f800000 - 0x3f3504f3; k += (ix >> 23) as i32 - 0x7f; ix = (ix & 0x007fffff) + 0x3f3504f3; ui = ix; x = f32::from_bits(ui); f = x - 1.0; s = f / (2.0 + f); z = s * s; w = z * z; t1 = w * (LG2 + w * LG4); t2 = z * (LG1 + w * LG3); r = t2 + t1; hfsq = 0.5 * f * f; hi = f - hfsq; ui = hi.to_bits(); ui &= 0xfffff000; hi = f32::from_bits(ui); lo = f - hi - hfsq + s * (hfsq + r); dk = k as f32; dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI + hi * IVLN10HI + dk * LOG10_2HI } libm-0.2.15/src/math/log1p.rs000064400000000000000000000113151046102023000137450ustar 00000000000000/* origin: FreeBSD /usr/src/lib/msun/src/s_log1p.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 log1p(double x) * Return the natural logarithm of 1+x. * * Method : * 1. Argument Reduction: find k and f such that * 1+x = 2^k * (1+f), * where sqrt(2)/2 < 1+f < sqrt(2) . * * Note. If k=0, then f=x is exact. However, if k!=0, then f * may not be representable exactly. In that case, a correction * term is need. Let u=1+x rounded. Let c = (1+x)-u, then * log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u), * and add back the correction term c/u. * (Note: when x > 2**53, one can simply return log(x)) * * 2. Approximation of log(1+f): See log.c * * 3. Finally, log1p(x) = k*ln2 + log(1+f) + c/u. See log.c * * Special cases: * log1p(x) is NaN with signal if x < -1 (including -INF) ; * log1p(+INF) is +INF; log1p(-1) is -INF with signal; * log1p(NaN) is that NaN with no signal. * * Accuracy: * according to an error analysis, the error is always less than * 1 ulp (unit in the last place). * * 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. * * Note: Assuming log() return accurate answer, the following * algorithm can be used to compute log1p(x) to within a few ULP: * * u = 1+x; * if(u==1.0) return x ; else * return log(u)*(x/(u-1.0)); * * See HP-15C Advanced Functions Handbook, p.193. */ use core::f64; const LN2_HI: f64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ const LN2_LO: f64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ /// The natural logarithm of 1+`x` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log1p(x: f64) -> f64 { let mut ui: u64 = x.to_bits(); let hfsq: f64; let mut f: f64 = 0.; let mut c: f64 = 0.; let s: f64; let z: f64; let r: f64; let w: f64; let t1: f64; let t2: f64; let dk: f64; let hx: u32; let mut hu: u32; let mut k: i32; hx = (ui >> 32) as u32; k = 1; if hx < 0x3fda827a || (hx >> 31) > 0 { /* 1+x < sqrt(2)+ */ if hx >= 0xbff00000 { /* x <= -1.0 */ if x == -1. { return x / 0.0; /* log1p(-1) = -inf */ } return (x - x) / 0.0; /* log1p(x<-1) = NaN */ } if hx << 1 < 0x3ca00000 << 1 { /* |x| < 2**-53 */ /* underflow if subnormal */ if (hx & 0x7ff00000) == 0 { force_eval!(x as f32); } return x; } if hx <= 0xbfd2bec4 { /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ k = 0; c = 0.; f = x; } } else if hx >= 0x7ff00000 { return x; } if k > 0 { ui = (1. + x).to_bits(); hu = (ui >> 32) as u32; hu += 0x3ff00000 - 0x3fe6a09e; k = (hu >> 20) as i32 - 0x3ff; /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ if k < 54 { c = if k >= 2 { 1. - (f64::from_bits(ui) - x) } else { x - (f64::from_bits(ui) - 1.) }; c /= f64::from_bits(ui); } else { c = 0.; } /* reduce u into [sqrt(2)/2, sqrt(2)] */ hu = (hu & 0x000fffff) + 0x3fe6a09e; ui = ((hu as u64) << 32) | (ui & 0xffffffff); f = f64::from_bits(ui) - 1.; } hfsq = 0.5 * f * f; s = f / (2.0 + f); z = s * s; w = z * z; t1 = w * (LG2 + w * (LG4 + w * LG6)); t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); r = t2 + t1; dk = k as f64; s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI } libm-0.2.15/src/math/log1pf.rs000064400000000000000000000054761046102023000141260ustar 00000000000000/* origin: FreeBSD /usr/src/lib/msun/src/s_log1pf.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::f32; const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ /// The natural logarithm of 1+`x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log1pf(x: f32) -> f32 { let mut ui: u32 = x.to_bits(); let hfsq: f32; let mut f: f32 = 0.; let mut c: f32 = 0.; let s: f32; let z: f32; let r: f32; let w: f32; let t1: f32; let t2: f32; let dk: f32; let ix: u32; let mut iu: u32; let mut k: i32; ix = ui; k = 1; if ix < 0x3ed413d0 || (ix >> 31) > 0 { /* 1+x < sqrt(2)+ */ if ix >= 0xbf800000 { /* x <= -1.0 */ if x == -1. { return x / 0.0; /* log1p(-1)=+inf */ } return (x - x) / 0.0; /* log1p(x<-1)=NaN */ } if ix << 1 < 0x33800000 << 1 { /* |x| < 2**-24 */ /* underflow if subnormal */ if (ix & 0x7f800000) == 0 { force_eval!(x * x); } return x; } if ix <= 0xbe95f619 { /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ k = 0; c = 0.; f = x; } } else if ix >= 0x7f800000 { return x; } if k > 0 { ui = (1. + x).to_bits(); iu = ui; iu += 0x3f800000 - 0x3f3504f3; k = (iu >> 23) as i32 - 0x7f; /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ if k < 25 { c = if k >= 2 { 1. - (f32::from_bits(ui) - x) } else { x - (f32::from_bits(ui) - 1.) }; c /= f32::from_bits(ui); } else { c = 0.; } /* reduce u into [sqrt(2)/2, sqrt(2)] */ iu = (iu & 0x007fffff) + 0x3f3504f3; ui = iu; f = f32::from_bits(ui) - 1.; } s = f / (2.0 + f); z = s * s; w = z * z; t1 = w * (LG2 + w * LG4); t2 = z * (LG1 + w * LG3); r = t2 + t1; hfsq = 0.5 * f * f; dk = k as f32; s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI } libm-0.2.15/src/math/log2.rs000064400000000000000000000063021046102023000135660ustar 00000000000000/* origin: FreeBSD /usr/src/lib/msun/src/e_log2.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. * ==================================================== */ /* * Return the base 2 logarithm of x. See log.c for most comments. * * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 * as in log.c, then combine and scale in extra precision: * log2(x) = (f - f*f/2 + r)/log(2) + k */ use core::f64; const IVLN2HI: f64 = 1.44269504072144627571e+00; /* 0x3ff71547, 0x65200000 */ const IVLN2LO: f64 = 1.67517131648865118353e-10; /* 0x3de705fc, 0x2eefa200 */ const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ /// The base 2 logarithm of `x` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log2(mut x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 let mut ui: u64 = x.to_bits(); let hfsq: f64; let f: f64; let s: f64; let z: f64; let r: f64; let mut w: f64; let t1: f64; let t2: f64; let y: f64; let mut hi: f64; let lo: f64; let mut val_hi: f64; let mut val_lo: f64; let mut hx: u32; let mut k: i32; hx = (ui >> 32) as u32; k = 0; if hx < 0x00100000 || (hx >> 31) > 0 { if ui << 1 == 0 { return -1. / (x * x); /* log(+-0)=-inf */ } if (hx >> 31) > 0 { return (x - x) / 0.0; /* log(-#) = NaN */ } /* subnormal number, scale x up */ k -= 54; x *= x1p54; ui = x.to_bits(); hx = (ui >> 32) as u32; } else if hx >= 0x7ff00000 { return x; } else if hx == 0x3ff00000 && ui << 32 == 0 { return 0.; } /* reduce x into [sqrt(2)/2, sqrt(2)] */ hx += 0x3ff00000 - 0x3fe6a09e; k += (hx >> 20) as i32 - 0x3ff; hx = (hx & 0x000fffff) + 0x3fe6a09e; ui = ((hx as u64) << 32) | (ui & 0xffffffff); x = f64::from_bits(ui); f = x - 1.0; hfsq = 0.5 * f * f; s = f / (2.0 + f); z = s * s; w = z * z; t1 = w * (LG2 + w * (LG4 + w * LG6)); t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); r = t2 + t1; /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ hi = f - hfsq; ui = hi.to_bits(); ui &= (-1i64 as u64) << 32; hi = f64::from_bits(ui); lo = f - hi - hfsq + s * (hfsq + r); val_hi = hi * IVLN2HI; val_lo = (lo + hi) * IVLN2LO + lo * IVLN2HI; /* spadd(val_hi, val_lo, y), except for not using double_t: */ y = k.into(); w = y + val_hi; val_lo += (y - w) + val_hi; val_hi = w; val_lo + val_hi } libm-0.2.15/src/math/log2f.rs000064400000000000000000000045611046102023000137410ustar 00000000000000/* origin: FreeBSD /usr/src/lib/msun/src/e_log2f.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. * ==================================================== */ /* * See comments in log2.c. */ use core::f32; const IVLN2HI: f32 = 1.4428710938e+00; /* 0x3fb8b000 */ const IVLN2LO: f32 = -1.7605285393e-04; /* 0xb9389ad4 */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ /// The base 2 logarithm of `x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log2f(mut x: f32) -> f32 { let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 let mut ui: u32 = x.to_bits(); let hfsq: f32; let f: f32; let s: f32; let z: f32; let r: f32; let w: f32; let t1: f32; let t2: f32; let mut hi: f32; let lo: f32; let mut ix: u32; let mut k: i32; ix = ui; k = 0; if ix < 0x00800000 || (ix >> 31) > 0 { /* x < 2**-126 */ if ix << 1 == 0 { return -1. / (x * x); /* log(+-0)=-inf */ } if (ix >> 31) > 0 { return (x - x) / 0.0; /* log(-#) = NaN */ } /* subnormal number, scale up x */ k -= 25; x *= x1p25f; ui = x.to_bits(); ix = ui; } else if ix >= 0x7f800000 { return x; } else if ix == 0x3f800000 { return 0.; } /* reduce x into [sqrt(2)/2, sqrt(2)] */ ix += 0x3f800000 - 0x3f3504f3; k += (ix >> 23) as i32 - 0x7f; ix = (ix & 0x007fffff) + 0x3f3504f3; ui = ix; x = f32::from_bits(ui); f = x - 1.0; s = f / (2.0 + f); z = s * s; w = z * z; t1 = w * (LG2 + w * LG4); t2 = z * (LG1 + w * LG3); r = t2 + t1; hfsq = 0.5 * f * f; hi = f - hfsq; ui = hi.to_bits(); ui &= 0xfffff000; hi = f32::from_bits(ui); lo = f - hi - hfsq + s * (hfsq + r); (lo + hi) * IVLN2LO + lo * IVLN2HI + hi * IVLN2HI + k as f32 } libm-0.2.15/src/math/logf.rs000064400000000000000000000041041046102023000136500ustar 00000000000000/* origin: FreeBSD /usr/src/lib/msun/src/e_logf.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 LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24*/ const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ /// The natural logarithm of `x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn logf(mut x: f32) -> f32 { let x1p25 = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 let mut ix = x.to_bits(); let mut k = 0i32; if (ix < 0x00800000) || ((ix >> 31) != 0) { /* x < 2**-126 */ if ix << 1 == 0 { return -1. / (x * x); /* log(+-0)=-inf */ } if (ix >> 31) != 0 { return (x - x) / 0.; /* log(-#) = NaN */ } /* subnormal number, scale up x */ k -= 25; x *= x1p25; ix = x.to_bits(); } else if ix >= 0x7f800000 { return x; } else if ix == 0x3f800000 { return 0.; } /* reduce x into [sqrt(2)/2, sqrt(2)] */ ix += 0x3f800000 - 0x3f3504f3; k += ((ix >> 23) as i32) - 0x7f; ix = (ix & 0x007fffff) + 0x3f3504f3; x = f32::from_bits(ix); let f = x - 1.; let s = f / (2. + f); let z = s * s; let w = z * z; let t1 = w * (LG2 + w * LG4); let t2 = z * (LG1 + w * LG3); let r = t2 + t1; let hfsq = 0.5 * f * f; let dk = k as f32; s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI } libm-0.2.15/src/math/mod.rs000064400000000000000000000227171046102023000135120ustar 00000000000000macro_rules! force_eval { ($e:expr) => { unsafe { ::core::ptr::read_volatile(&$e) } }; } #[cfg(not(debug_assertions))] macro_rules! i { ($array:expr, $index:expr) => { unsafe { *$array.get_unchecked($index) } }; ($array:expr, $index:expr, = , $rhs:expr) => { unsafe { *$array.get_unchecked_mut($index) = $rhs; } }; ($array:expr, $index:expr, += , $rhs:expr) => { unsafe { *$array.get_unchecked_mut($index) += $rhs; } }; ($array:expr, $index:expr, -= , $rhs:expr) => { unsafe { *$array.get_unchecked_mut($index) -= $rhs; } }; ($array:expr, $index:expr, &= , $rhs:expr) => { unsafe { *$array.get_unchecked_mut($index) &= $rhs; } }; ($array:expr, $index:expr, == , $rhs:expr) => { unsafe { *$array.get_unchecked_mut($index) == $rhs } }; } #[cfg(debug_assertions)] macro_rules! i { ($array:expr, $index:expr) => { *$array.get($index).unwrap() }; ($array:expr, $index:expr, = , $rhs:expr) => { *$array.get_mut($index).unwrap() = $rhs; }; ($array:expr, $index:expr, -= , $rhs:expr) => { *$array.get_mut($index).unwrap() -= $rhs; }; ($array:expr, $index:expr, += , $rhs:expr) => { *$array.get_mut($index).unwrap() += $rhs; }; ($array:expr, $index:expr, &= , $rhs:expr) => { *$array.get_mut($index).unwrap() &= $rhs; }; ($array:expr, $index:expr, == , $rhs:expr) => { *$array.get_mut($index).unwrap() == $rhs }; } // Temporary macro to avoid panic codegen for division (in debug mode too). At // the time of this writing this is only used in a few places, and once // rust-lang/rust#72751 is fixed then this macro will no longer be necessary and // the native `/` operator can be used and panics won't be codegen'd. #[cfg(any(debug_assertions, not(intrinsics_enabled)))] macro_rules! div { ($a:expr, $b:expr) => { $a / $b }; } #[cfg(all(not(debug_assertions), intrinsics_enabled))] macro_rules! div { ($a:expr, $b:expr) => { unsafe { core::intrinsics::unchecked_div($a, $b) } }; } // `support` may be public for testing #[macro_use] #[cfg(feature = "unstable-public-internals")] pub mod support; #[macro_use] #[cfg(not(feature = "unstable-public-internals"))] pub(crate) mod support; cfg_if! { if #[cfg(feature = "unstable-public-internals")] { pub mod generic; } else { mod generic; } } // Private modules mod arch; mod expo2; mod k_cos; mod k_cosf; mod k_expo2; mod k_expo2f; mod k_sin; mod k_sinf; mod k_tan; mod k_tanf; mod rem_pio2; mod rem_pio2_large; mod rem_pio2f; // Private re-imports use self::expo2::expo2; use self::k_cos::k_cos; use self::k_cosf::k_cosf; use self::k_expo2::k_expo2; use self::k_expo2f::k_expo2f; use self::k_sin::k_sin; use self::k_sinf::k_sinf; use self::k_tan::k_tan; use self::k_tanf::k_tanf; use self::rem_pio2::rem_pio2; use self::rem_pio2_large::rem_pio2_large; use self::rem_pio2f::rem_pio2f; #[allow(unused_imports)] use self::support::{CastFrom, CastInto, DFloat, DInt, Float, HFloat, HInt, Int, IntTy, MinInt}; // Public modules mod acos; mod acosf; mod acosh; mod acoshf; mod asin; mod asinf; mod asinh; mod asinhf; mod atan; mod atan2; mod atan2f; mod atanf; mod atanh; mod atanhf; mod cbrt; mod cbrtf; mod ceil; mod copysign; mod cos; mod cosf; mod cosh; mod coshf; mod erf; mod erff; mod exp; mod exp10; mod exp10f; mod exp2; mod exp2f; mod expf; mod expm1; mod expm1f; mod fabs; mod fdim; mod floor; mod fma; mod fmin_fmax; mod fminimum_fmaximum; mod fminimum_fmaximum_num; mod fmod; mod frexp; mod frexpf; mod hypot; mod hypotf; mod ilogb; mod ilogbf; mod j0; mod j0f; mod j1; mod j1f; mod jn; mod jnf; mod ldexp; mod lgamma; mod lgamma_r; mod lgammaf; mod lgammaf_r; mod log; mod log10; mod log10f; mod log1p; mod log1pf; mod log2; mod log2f; mod logf; mod modf; mod modff; mod nextafter; mod nextafterf; mod pow; mod powf; mod remainder; mod remainderf; mod remquo; mod remquof; mod rint; mod round; mod roundeven; mod scalbn; mod sin; mod sincos; mod sincosf; mod sinf; mod sinh; mod sinhf; mod sqrt; mod tan; mod tanf; mod tanh; mod tanhf; mod tgamma; mod tgammaf; mod trunc; // Use separated imports instead of {}-grouped imports for easier merging. pub use self::acos::acos; pub use self::acosf::acosf; pub use self::acosh::acosh; pub use self::acoshf::acoshf; pub use self::asin::asin; pub use self::asinf::asinf; pub use self::asinh::asinh; pub use self::asinhf::asinhf; pub use self::atan::atan; pub use self::atan2::atan2; pub use self::atan2f::atan2f; pub use self::atanf::atanf; pub use self::atanh::atanh; pub use self::atanhf::atanhf; pub use self::cbrt::cbrt; pub use self::cbrtf::cbrtf; pub use self::ceil::{ceil, ceilf}; pub use self::copysign::{copysign, copysignf}; pub use self::cos::cos; pub use self::cosf::cosf; pub use self::cosh::cosh; pub use self::coshf::coshf; pub use self::erf::{erf, erfc}; pub use self::erff::{erfcf, erff}; pub use self::exp::exp; pub use self::exp2::exp2; pub use self::exp2f::exp2f; pub use self::exp10::exp10; pub use self::exp10f::exp10f; pub use self::expf::expf; pub use self::expm1::expm1; pub use self::expm1f::expm1f; pub use self::fabs::{fabs, fabsf}; pub use self::fdim::{fdim, fdimf}; pub use self::floor::{floor, floorf}; pub use self::fma::{fma, fmaf}; pub use self::fmin_fmax::{fmax, fmaxf, fmin, fminf}; pub use self::fminimum_fmaximum::{fmaximum, fmaximumf, fminimum, fminimumf}; pub use self::fminimum_fmaximum_num::{fmaximum_num, fmaximum_numf, fminimum_num, fminimum_numf}; pub use self::fmod::{fmod, fmodf}; pub use self::frexp::frexp; pub use self::frexpf::frexpf; pub use self::hypot::hypot; pub use self::hypotf::hypotf; pub use self::ilogb::ilogb; pub use self::ilogbf::ilogbf; pub use self::j0::{j0, y0}; pub use self::j0f::{j0f, y0f}; pub use self::j1::{j1, y1}; pub use self::j1f::{j1f, y1f}; pub use self::jn::{jn, yn}; pub use self::jnf::{jnf, ynf}; pub use self::ldexp::{ldexp, ldexpf}; pub use self::lgamma::lgamma; pub use self::lgamma_r::lgamma_r; pub use self::lgammaf::lgammaf; pub use self::lgammaf_r::lgammaf_r; pub use self::log::log; pub use self::log1p::log1p; pub use self::log1pf::log1pf; pub use self::log2::log2; pub use self::log2f::log2f; pub use self::log10::log10; pub use self::log10f::log10f; pub use self::logf::logf; pub use self::modf::modf; pub use self::modff::modff; pub use self::nextafter::nextafter; pub use self::nextafterf::nextafterf; pub use self::pow::pow; pub use self::powf::powf; pub use self::remainder::remainder; pub use self::remainderf::remainderf; pub use self::remquo::remquo; pub use self::remquof::remquof; pub use self::rint::{rint, rintf}; pub use self::round::{round, roundf}; pub use self::roundeven::{roundeven, roundevenf}; pub use self::scalbn::{scalbn, scalbnf}; pub use self::sin::sin; pub use self::sincos::sincos; pub use self::sincosf::sincosf; pub use self::sinf::sinf; pub use self::sinh::sinh; pub use self::sinhf::sinhf; pub use self::sqrt::{sqrt, sqrtf}; pub use self::tan::tan; pub use self::tanf::tanf; pub use self::tanh::tanh; pub use self::tanhf::tanhf; pub use self::tgamma::tgamma; pub use self::tgammaf::tgammaf; pub use self::trunc::{trunc, truncf}; cfg_if! { if #[cfg(f16_enabled)] { // verify-sorted-start pub use self::ceil::ceilf16; pub use self::copysign::copysignf16; pub use self::fabs::fabsf16; pub use self::fdim::fdimf16; pub use self::floor::floorf16; pub use self::fmin_fmax::{fmaxf16, fminf16}; pub use self::fminimum_fmaximum::{fmaximumf16, fminimumf16}; pub use self::fminimum_fmaximum_num::{fmaximum_numf16, fminimum_numf16}; pub use self::fmod::fmodf16; pub use self::ldexp::ldexpf16; pub use self::rint::rintf16; pub use self::round::roundf16; pub use self::roundeven::roundevenf16; pub use self::scalbn::scalbnf16; pub use self::sqrt::sqrtf16; pub use self::trunc::truncf16; // verify-sorted-end #[allow(unused_imports)] pub(crate) use self::fma::fmaf16; } } cfg_if! { if #[cfg(f128_enabled)] { // verify-sorted-start pub use self::ceil::ceilf128; pub use self::copysign::copysignf128; pub use self::fabs::fabsf128; pub use self::fdim::fdimf128; pub use self::floor::floorf128; pub use self::fma::fmaf128; pub use self::fmin_fmax::{fmaxf128, fminf128}; pub use self::fminimum_fmaximum::{fmaximumf128, fminimumf128}; pub use self::fminimum_fmaximum_num::{fmaximum_numf128, fminimum_numf128}; pub use self::fmod::fmodf128; pub use self::ldexp::ldexpf128; pub use self::rint::rintf128; pub use self::round::roundf128; pub use self::roundeven::roundevenf128; pub use self::scalbn::scalbnf128; pub use self::sqrt::sqrtf128; pub use self::trunc::truncf128; // verify-sorted-end } } #[inline] fn get_high_word(x: f64) -> u32 { (x.to_bits() >> 32) as u32 } #[inline] fn get_low_word(x: f64) -> u32 { x.to_bits() as u32 } #[inline] fn with_set_high_word(f: f64, hi: u32) -> f64 { let mut tmp = f.to_bits(); tmp &= 0x00000000_ffffffff; tmp |= (hi as u64) << 32; f64::from_bits(tmp) } #[inline] fn with_set_low_word(f: f64, lo: u32) -> f64 { let mut tmp = f.to_bits(); tmp &= 0xffffffff_00000000; tmp |= lo as u64; f64::from_bits(tmp) } #[inline] fn combine_words(hi: u32, lo: u32) -> f64 { f64::from_bits(((hi as u64) << 32) | lo as u64) } libm-0.2.15/src/math/modf.rs000064400000000000000000000014301046102023000136450ustar 00000000000000#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn modf(x: f64) -> (f64, f64) { let rv2: f64; let mut u = x.to_bits(); let mask: u64; let e = (((u >> 52) & 0x7ff) as i32) - 0x3ff; /* no fractional part */ if e >= 52 { rv2 = x; if e == 0x400 && (u << 12) != 0 { /* nan */ return (x, rv2); } u &= 1 << 63; return (f64::from_bits(u), rv2); } /* no integral part*/ if e < 0 { u &= 1 << 63; rv2 = f64::from_bits(u); return (x, rv2); } mask = ((!0) >> 12) >> e; if (u & mask) == 0 { rv2 = x; u &= 1 << 63; return (f64::from_bits(u), rv2); } u &= !mask; rv2 = f64::from_bits(u); return (x - rv2, rv2); } libm-0.2.15/src/math/modff.rs000064400000000000000000000014411046102023000140150ustar 00000000000000#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn modff(x: f32) -> (f32, f32) { let rv2: f32; let mut u: u32 = x.to_bits(); let mask: u32; let e = (((u >> 23) & 0xff) as i32) - 0x7f; /* no fractional part */ if e >= 23 { rv2 = x; if e == 0x80 && (u << 9) != 0 { /* nan */ return (x, rv2); } u &= 0x80000000; return (f32::from_bits(u), rv2); } /* no integral part */ if e < 0 { u &= 0x80000000; rv2 = f32::from_bits(u); return (x, rv2); } mask = 0x007fffff >> e; if (u & mask) == 0 { rv2 = x; u &= 0x80000000; return (f32::from_bits(u), rv2); } u &= !mask; rv2 = f32::from_bits(u); return (x - rv2, rv2); } libm-0.2.15/src/math/nextafter.rs000064400000000000000000000015651046102023000147310ustar 00000000000000#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn nextafter(x: f64, y: f64) -> f64 { if x.is_nan() || y.is_nan() { return x + y; } let mut ux_i = x.to_bits(); let uy_i = y.to_bits(); if ux_i == uy_i { return y; } let ax = ux_i & (!1_u64 / 2); let ay = uy_i & (!1_u64 / 2); if ax == 0 { if ay == 0 { return y; } ux_i = (uy_i & (1_u64 << 63)) | 1; } else if ax > ay || ((ux_i ^ uy_i) & (1_u64 << 63)) != 0 { ux_i -= 1; } else { ux_i += 1; } let e = (ux_i >> 52) & 0x7ff; // raise overflow if ux.f is infinite and x is finite if e == 0x7ff { force_eval!(x + x); } let ux_f = f64::from_bits(ux_i); // raise underflow if ux.f is subnormal or zero if e == 0 { force_eval!(x * x + ux_f * ux_f); } ux_f } libm-0.2.15/src/math/nextafterf.rs000064400000000000000000000016141046102023000150720ustar 00000000000000#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn nextafterf(x: f32, y: f32) -> f32 { if x.is_nan() || y.is_nan() { return x + y; } let mut ux_i = x.to_bits(); let uy_i = y.to_bits(); if ux_i == uy_i { return y; } let ax = ux_i & 0x7fff_ffff_u32; let ay = uy_i & 0x7fff_ffff_u32; if ax == 0 { if ay == 0 { return y; } ux_i = (uy_i & 0x8000_0000_u32) | 1; } else if ax > ay || ((ux_i ^ uy_i) & 0x8000_0000_u32) != 0 { ux_i -= 1; } else { ux_i += 1; } let e = ux_i & 0x7f80_0000_u32; // raise overflow if ux_f is infinite and x is finite if e == 0x7f80_0000_u32 { force_eval!(x + x); } let ux_f = f32::from_bits(ux_i); // raise underflow if ux_f is subnormal or zero if e == 0 { force_eval!(x * x + ux_f * ux_f); } ux_f } libm-0.2.15/src/math/pow.rs000064400000000000000000000517241046102023000135400ustar 00000000000000/* origin: FreeBSD /usr/src/lib/msun/src/e_pow.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. * ==================================================== */ // pow(x,y) return x**y // // n // Method: Let x = 2 * (1+f) // 1. Compute and return log2(x) in two pieces: // log2(x) = w1 + w2, // where w1 has 53-24 = 29 bit trailing zeros. // 2. Perform y*log2(x) = n+y' by simulating multi-precision // arithmetic, where |y'|<=0.5. // 3. Return x**y = 2**n*exp(y'*log2) // // Special cases: // 1. (anything) ** 0 is 1 // 2. 1 ** (anything) is 1 // 3. (anything except 1) ** NAN is NAN // 4. NAN ** (anything except 0) is NAN // 5. +-(|x| > 1) ** +INF is +INF // 6. +-(|x| > 1) ** -INF is +0 // 7. +-(|x| < 1) ** +INF is +0 // 8. +-(|x| < 1) ** -INF is +INF // 9. -1 ** +-INF is 1 // 10. +0 ** (+anything except 0, NAN) is +0 // 11. -0 ** (+anything except 0, NAN, odd integer) is +0 // 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero // 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero // 14. -0 ** (+odd integer) is -0 // 15. -0 ** (-odd integer) is -INF, raise divbyzero // 16. +INF ** (+anything except 0,NAN) is +INF // 17. +INF ** (-anything except 0,NAN) is +0 // 18. -INF ** (+odd integer) is -INF // 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer) // 20. (anything) ** 1 is (anything) // 21. (anything) ** -1 is 1/(anything) // 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) // 23. (-anything except 0 and inf) ** (non-integer) is NAN // // Accuracy: // pow(x,y) returns x**y nearly rounded. In particular // pow(integer,integer) // always returns the correct integer provided it is // representable. // // 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::{fabs, get_high_word, scalbn, sqrt, with_set_high_word, with_set_low_word}; const BP: [f64; 2] = [1.0, 1.5]; const DP_H: [f64; 2] = [0.0, 5.84962487220764160156e-01]; /* 0x3fe2b803_40000000 */ const DP_L: [f64; 2] = [0.0, 1.35003920212974897128e-08]; /* 0x3E4CFDEB, 0x43CFD006 */ const TWO53: f64 = 9007199254740992.0; /* 0x43400000_00000000 */ const HUGE: f64 = 1.0e300; const TINY: f64 = 1.0e-300; // poly coefs for (3/2)*(log(x)-2s-2/3*s**3: const L1: f64 = 5.99999999999994648725e-01; /* 0x3fe33333_33333303 */ const L2: f64 = 4.28571428578550184252e-01; /* 0x3fdb6db6_db6fabff */ const L3: f64 = 3.33333329818377432918e-01; /* 0x3fd55555_518f264d */ const L4: f64 = 2.72728123808534006489e-01; /* 0x3fd17460_a91d4101 */ const L5: f64 = 2.30660745775561754067e-01; /* 0x3fcd864a_93c9db65 */ const L6: f64 = 2.06975017800338417784e-01; /* 0x3fca7e28_4a454eef */ const P1: f64 = 1.66666666666666019037e-01; /* 0x3fc55555_5555553e */ const P2: f64 = -2.77777777770155933842e-03; /* 0xbf66c16c_16bebd93 */ const P3: f64 = 6.61375632143793436117e-05; /* 0x3f11566a_af25de2c */ const P4: f64 = -1.65339022054652515390e-06; /* 0xbebbbd41_c5d26bf1 */ const P5: f64 = 4.13813679705723846039e-08; /* 0x3e663769_72bea4d0 */ const LG2: f64 = 6.93147180559945286227e-01; /* 0x3fe62e42_fefa39ef */ const LG2_H: f64 = 6.93147182464599609375e-01; /* 0x3fe62e43_00000000 */ const LG2_L: f64 = -1.90465429995776804525e-09; /* 0xbe205c61_0ca86c39 */ const OVT: f64 = 8.0085662595372944372e-017; /* -(1024-log2(ovfl+.5ulp)) */ const CP: f64 = 9.61796693925975554329e-01; /* 0x3feec709_dc3a03fd =2/(3ln2) */ const CP_H: f64 = 9.61796700954437255859e-01; /* 0x3feec709_e0000000 =(float)cp */ const CP_L: f64 = -7.02846165095275826516e-09; /* 0xbe3e2fe0_145b01f5 =tail of cp_h*/ const IVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547_652b82fe =1/ln2 */ const IVLN2_H: f64 = 1.44269502162933349609e+00; /* 0x3ff71547_60000000 =24b 1/ln2*/ const IVLN2_L: f64 = 1.92596299112661746887e-08; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/ /// Returns `x` to the power of `y` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn pow(x: f64, y: f64) -> f64 { let t1: f64; let t2: f64; let (hx, lx): (i32, u32) = ((x.to_bits() >> 32) as i32, x.to_bits() as u32); let (hy, ly): (i32, u32) = ((y.to_bits() >> 32) as i32, y.to_bits() as u32); let mut ix: i32 = hx & 0x7fffffff_i32; let iy: i32 = hy & 0x7fffffff_i32; /* x**0 = 1, even if x is NaN */ if ((iy as u32) | ly) == 0 { return 1.0; } /* 1**y = 1, even if y is NaN */ if hx == 0x3ff00000 && lx == 0 { return 1.0; } /* NaN if either arg is NaN */ if ix > 0x7ff00000 || (ix == 0x7ff00000 && lx != 0) || iy > 0x7ff00000 || (iy == 0x7ff00000 && ly != 0) { return x + y; } /* determine if y is an odd int when x < 0 * yisint = 0 ... y is not an integer * yisint = 1 ... y is an odd int * yisint = 2 ... y is an even int */ let mut yisint: i32 = 0; let mut k: i32; let mut j: i32; if hx < 0 { if iy >= 0x43400000 { yisint = 2; /* even integer y */ } else if iy >= 0x3ff00000 { k = (iy >> 20) - 0x3ff; /* exponent */ if k > 20 { j = (ly >> (52 - k)) as i32; if (j << (52 - k)) == (ly as i32) { yisint = 2 - (j & 1); } } else if ly == 0 { j = iy >> (20 - k); if (j << (20 - k)) == iy { yisint = 2 - (j & 1); } } } } if ly == 0 { /* special value of y */ if iy == 0x7ff00000 { /* y is +-inf */ return if ((ix - 0x3ff00000) | (lx as i32)) == 0 { /* (-1)**+-inf is 1 */ 1.0 } else if ix >= 0x3ff00000 { /* (|x|>1)**+-inf = inf,0 */ if hy >= 0 { y } else { 0.0 } } else { /* (|x|<1)**+-inf = 0,inf */ if hy >= 0 { 0.0 } else { -y } }; } if iy == 0x3ff00000 { /* y is +-1 */ return if hy >= 0 { x } else { 1.0 / x }; } if hy == 0x40000000 { /* y is 2 */ return x * x; } if hy == 0x3fe00000 { /* y is 0.5 */ if hx >= 0 { /* x >= +0 */ return sqrt(x); } } } let mut ax: f64 = fabs(x); if lx == 0 { /* special value of x */ if ix == 0x7ff00000 || ix == 0 || ix == 0x3ff00000 { /* x is +-0,+-inf,+-1 */ let mut z: f64 = ax; if hy < 0 { /* z = (1/|x|) */ z = 1.0 / z; } if hx < 0 { if ((ix - 0x3ff00000) | yisint) == 0 { z = (z - z) / (z - z); /* (-1)**non-int is NaN */ } else if yisint == 1 { z = -z; /* (x<0)**odd = -(|x|**odd) */ } } return z; } } let mut s: f64 = 1.0; /* sign of result */ if hx < 0 { if yisint == 0 { /* (x<0)**(non-int) is NaN */ return (x - x) / (x - x); } if yisint == 1 { /* (x<0)**(odd int) */ s = -1.0; } } /* |y| is HUGE */ if iy > 0x41e00000 { /* if |y| > 2**31 */ if iy > 0x43f00000 { /* if |y| > 2**64, must o/uflow */ if ix <= 0x3fefffff { return if hy < 0 { HUGE * HUGE } else { TINY * TINY }; } if ix >= 0x3ff00000 { return if hy > 0 { HUGE * HUGE } else { TINY * TINY }; } } /* over/underflow if x is not close to one */ if ix < 0x3fefffff { return if hy < 0 { s * HUGE * HUGE } else { s * TINY * TINY }; } if ix > 0x3ff00000 { return if hy > 0 { s * HUGE * HUGE } else { s * TINY * TINY }; } /* now |1-x| is TINY <= 2**-20, suffice to compute log(x) by x-x^2/2+x^3/3-x^4/4 */ let t: f64 = ax - 1.0; /* t has 20 trailing zeros */ let w: f64 = (t * t) * (0.5 - t * (0.3333333333333333333333 - t * 0.25)); let u: f64 = IVLN2_H * t; /* ivln2_h has 21 sig. bits */ let v: f64 = t * IVLN2_L - w * IVLN2; t1 = with_set_low_word(u + v, 0); t2 = v - (t1 - u); } else { // double ss,s2,s_h,s_l,t_h,t_l; let mut n: i32 = 0; if ix < 0x00100000 { /* take care subnormal number */ ax *= TWO53; n -= 53; ix = get_high_word(ax) as i32; } n += (ix >> 20) - 0x3ff; j = ix & 0x000fffff; /* determine interval */ let k: i32; ix = j | 0x3ff00000; /* normalize ix */ if j <= 0x3988E { /* |x|> 1) | 0x20000000) + 0x00080000 + ((k as u32) << 18), ); let t_l: f64 = ax - (t_h - i!(BP, k as usize)); let s_l: f64 = v * ((u - s_h * t_h) - s_h * t_l); /* compute log(ax) */ let s2: f64 = ss * ss; let mut r: f64 = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); r += s_l * (s_h + ss); let s2: f64 = s_h * s_h; let t_h: f64 = with_set_low_word(3.0 + s2 + r, 0); let t_l: f64 = r - ((t_h - 3.0) - s2); /* u+v = ss*(1+...) */ let u: f64 = s_h * t_h; let v: f64 = s_l * t_h + t_l * ss; /* 2/(3log2)*(ss+...) */ let p_h: f64 = with_set_low_word(u + v, 0); let p_l = v - (p_h - u); let z_h: f64 = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ let z_l: f64 = CP_L * p_h + p_l * CP + i!(DP_L, k as usize); /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ let t: f64 = n as f64; t1 = with_set_low_word(((z_h + z_l) + i!(DP_H, k as usize)) + t, 0); t2 = z_l - (((t1 - t) - i!(DP_H, k as usize)) - z_h); } /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ let y1: f64 = with_set_low_word(y, 0); let p_l: f64 = (y - y1) * t1 + y * t2; let mut p_h: f64 = y1 * t1; let z: f64 = p_l + p_h; let mut j: i32 = (z.to_bits() >> 32) as i32; let i: i32 = z.to_bits() as i32; // let (j, i): (i32, i32) = ((z.to_bits() >> 32) as i32, z.to_bits() as i32); if j >= 0x40900000 { /* z >= 1024 */ if (j - 0x40900000) | i != 0 { /* if z > 1024 */ return s * HUGE * HUGE; /* overflow */ } if p_l + OVT > z - p_h { return s * HUGE * HUGE; /* overflow */ } } else if (j & 0x7fffffff) >= 0x4090cc00 { /* z <= -1075 */ // FIXME: instead of abs(j) use unsigned j if (((j as u32) - 0xc090cc00) | (i as u32)) != 0 { /* z < -1075 */ return s * TINY * TINY; /* underflow */ } if p_l <= z - p_h { return s * TINY * TINY; /* underflow */ } } /* compute 2**(p_h+p_l) */ let i: i32 = j & 0x7fffffff_i32; k = (i >> 20) - 0x3ff; let mut n: i32 = 0; if i > 0x3fe00000 { /* if |z| > 0.5, set n = [z+0.5] */ n = j + (0x00100000 >> (k + 1)); k = ((n & 0x7fffffff) >> 20) - 0x3ff; /* new k for n */ let t: f64 = with_set_high_word(0.0, (n & !(0x000fffff >> k)) as u32); n = ((n & 0x000fffff) | 0x00100000) >> (20 - k); if j < 0 { n = -n; } p_h -= t; } let t: f64 = with_set_low_word(p_l + p_h, 0); let u: f64 = t * LG2_H; let v: f64 = (p_l - (t - p_h)) * LG2 + t * LG2_L; let mut z: f64 = u + v; let w: f64 = v - (z - u); let t: f64 = z * z; let t1: f64 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); let r: f64 = (z * t1) / (t1 - 2.0) - (w + z * w); z = 1.0 - (r - z); j = get_high_word(z) as i32; j += n << 20; if (j >> 20) <= 0 { /* subnormal output */ z = scalbn(z, n); } else { z = with_set_high_word(z, j as u32); } s * z } #[cfg(test)] mod tests { extern crate core; use self::core::f64::consts::{E, PI}; use super::pow; const POS_ZERO: &[f64] = &[0.0]; const NEG_ZERO: &[f64] = &[-0.0]; const POS_ONE: &[f64] = &[1.0]; const NEG_ONE: &[f64] = &[-1.0]; const POS_FLOATS: &[f64] = &[99.0 / 70.0, E, PI]; const NEG_FLOATS: &[f64] = &[-99.0 / 70.0, -E, -PI]; const POS_SMALL_FLOATS: &[f64] = &[(1.0 / 2.0), f64::MIN_POSITIVE, f64::EPSILON]; const NEG_SMALL_FLOATS: &[f64] = &[-(1.0 / 2.0), -f64::MIN_POSITIVE, -f64::EPSILON]; const POS_EVENS: &[f64] = &[2.0, 6.0, 8.0, 10.0, 22.0, 100.0, f64::MAX]; const NEG_EVENS: &[f64] = &[f64::MIN, -100.0, -22.0, -10.0, -8.0, -6.0, -2.0]; const POS_ODDS: &[f64] = &[3.0, 7.0]; const NEG_ODDS: &[f64] = &[-7.0, -3.0]; const NANS: &[f64] = &[f64::NAN]; const POS_INF: &[f64] = &[f64::INFINITY]; const NEG_INF: &[f64] = &[f64::NEG_INFINITY]; const ALL: &[&[f64]] = &[ POS_ZERO, NEG_ZERO, NANS, NEG_SMALL_FLOATS, POS_SMALL_FLOATS, NEG_FLOATS, POS_FLOATS, NEG_EVENS, POS_EVENS, NEG_ODDS, POS_ODDS, NEG_INF, POS_INF, NEG_ONE, POS_ONE, ]; const POS: &[&[f64]] = &[POS_ZERO, POS_ODDS, POS_ONE, POS_FLOATS, POS_EVENS, POS_INF]; const NEG: &[&[f64]] = &[NEG_ZERO, NEG_ODDS, NEG_ONE, NEG_FLOATS, NEG_EVENS, NEG_INF]; fn pow_test(base: f64, exponent: f64, expected: f64) { let res = pow(base, exponent); assert!( if expected.is_nan() { res.is_nan() } else { pow(base, exponent) == expected }, "{base} ** {exponent} was {res} instead of {expected}", ); } fn test_sets_as_base(sets: &[&[f64]], exponent: f64, expected: f64) { sets.iter() .for_each(|s| s.iter().for_each(|val| pow_test(*val, exponent, expected))); } fn test_sets_as_exponent(base: f64, sets: &[&[f64]], expected: f64) { sets.iter() .for_each(|s| s.iter().for_each(|val| pow_test(base, *val, expected))); } fn test_sets(sets: &[&[f64]], computed: &dyn Fn(f64) -> f64, expected: &dyn Fn(f64) -> f64) { sets.iter().for_each(|s| { s.iter().for_each(|val| { let exp = expected(*val); let res = computed(*val); #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] let exp = force_eval!(exp); #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] let res = force_eval!(res); assert!( if exp.is_nan() { res.is_nan() } else { exp == res }, "test for {val} was {res} instead of {exp}", ); }) }); } #[test] fn zero_as_exponent() { test_sets_as_base(ALL, 0.0, 1.0); test_sets_as_base(ALL, -0.0, 1.0); } #[test] fn one_as_base() { test_sets_as_exponent(1.0, ALL, 1.0); } #[test] fn nan_inputs() { // NAN as the base: // (f64::NAN ^ anything *but 0* should be f64::NAN) test_sets_as_exponent(f64::NAN, &ALL[2..], f64::NAN); // f64::NAN as the exponent: // (anything *but 1* ^ f64::NAN should be f64::NAN) test_sets_as_base(&ALL[..(ALL.len() - 2)], f64::NAN, f64::NAN); } #[test] fn infinity_as_base() { // Positive Infinity as the base: // (+Infinity ^ positive anything but 0 and f64::NAN should be +Infinity) test_sets_as_exponent(f64::INFINITY, &POS[1..], f64::INFINITY); // (+Infinity ^ negative anything except 0 and f64::NAN should be 0.0) test_sets_as_exponent(f64::INFINITY, &NEG[1..], 0.0); // Negative Infinity as the base: // (-Infinity ^ positive odd ints should be -Infinity) test_sets_as_exponent(f64::NEG_INFINITY, &[POS_ODDS], f64::NEG_INFINITY); // (-Infinity ^ anything but odd ints should be == -0 ^ (-anything)) // We can lump in pos/neg odd ints here because they don't seem to // cause panics (div by zero) in release mode (I think). test_sets(ALL, &|v: f64| pow(f64::NEG_INFINITY, v), &|v: f64| { pow(-0.0, -v) }); } #[test] fn infinity_as_exponent() { // Positive/Negative base greater than 1: // (pos/neg > 1 ^ Infinity should be Infinity - note this excludes f64::NAN as the base) test_sets_as_base(&ALL[5..(ALL.len() - 2)], f64::INFINITY, f64::INFINITY); // (pos/neg > 1 ^ -Infinity should be 0.0) test_sets_as_base(&ALL[5..ALL.len() - 2], f64::NEG_INFINITY, 0.0); // Positive/Negative base less than 1: let base_below_one = &[POS_ZERO, NEG_ZERO, NEG_SMALL_FLOATS, POS_SMALL_FLOATS]; // (pos/neg < 1 ^ Infinity should be 0.0 - this also excludes f64::NAN as the base) test_sets_as_base(base_below_one, f64::INFINITY, 0.0); // (pos/neg < 1 ^ -Infinity should be Infinity) test_sets_as_base(base_below_one, f64::NEG_INFINITY, f64::INFINITY); // Positive/Negative 1 as the base: // (pos/neg 1 ^ Infinity should be 1) test_sets_as_base(&[NEG_ONE, POS_ONE], f64::INFINITY, 1.0); // (pos/neg 1 ^ -Infinity should be 1) test_sets_as_base(&[NEG_ONE, POS_ONE], f64::NEG_INFINITY, 1.0); } #[test] fn zero_as_base() { // Positive Zero as the base: // (+0 ^ anything positive but 0 and f64::NAN should be +0) test_sets_as_exponent(0.0, &POS[1..], 0.0); // (+0 ^ anything negative but 0 and f64::NAN should be Infinity) // (this should panic because we're dividing by zero) test_sets_as_exponent(0.0, &NEG[1..], f64::INFINITY); // Negative Zero as the base: // (-0 ^ anything positive but 0, f64::NAN, and odd ints should be +0) test_sets_as_exponent(-0.0, &POS[3..], 0.0); // (-0 ^ anything negative but 0, f64::NAN, and odd ints should be Infinity) // (should panic because of divide by zero) test_sets_as_exponent(-0.0, &NEG[3..], f64::INFINITY); // (-0 ^ positive odd ints should be -0) test_sets_as_exponent(-0.0, &[POS_ODDS], -0.0); // (-0 ^ negative odd ints should be -Infinity) // (should panic because of divide by zero) test_sets_as_exponent(-0.0, &[NEG_ODDS], f64::NEG_INFINITY); } #[test] fn special_cases() { // One as the exponent: // (anything ^ 1 should be anything - i.e. the base) test_sets(ALL, &|v: f64| pow(v, 1.0), &|v: f64| v); // Negative One as the exponent: // (anything ^ -1 should be 1/anything) test_sets(ALL, &|v: f64| pow(v, -1.0), &|v: f64| 1.0 / v); // Factoring -1 out: // (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^ integer)) [POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS] .iter() .for_each(|int_set| { int_set.iter().for_each(|int| { test_sets(ALL, &|v: f64| pow(-v, *int), &|v: f64| { pow(-1.0, *int) * pow(v, *int) }); }) }); // Negative base (imaginary results): // (-anything except 0 and Infinity ^ non-integer should be NAN) NEG[1..(NEG.len() - 1)].iter().for_each(|set| { set.iter().for_each(|val| { test_sets(&ALL[3..7], &|v: f64| pow(*val, v), &|_| f64::NAN); }) }); } #[test] fn normal_cases() { assert_eq!(pow(2.0, 20.0), (1 << 20) as f64); assert_eq!(pow(-1.0, 9.0), -1.0); assert!(pow(-1.0, 2.2).is_nan()); assert!(pow(-1.0, -1.14).is_nan()); } } libm-0.2.15/src/math/powf.rs000064400000000000000000000236071046102023000137050ustar 00000000000000/* origin: FreeBSD /usr/src/lib/msun/src/e_powf.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 core::cmp::Ordering; use super::{fabsf, scalbnf, sqrtf}; const BP: [f32; 2] = [1.0, 1.5]; const DP_H: [f32; 2] = [0.0, 5.84960938e-01]; /* 0x3f15c000 */ const DP_L: [f32; 2] = [0.0, 1.56322085e-06]; /* 0x35d1cfdc */ const TWO24: f32 = 16777216.0; /* 0x4b800000 */ const HUGE: f32 = 1.0e30; const TINY: f32 = 1.0e-30; const L1: f32 = 6.0000002384e-01; /* 0x3f19999a */ const L2: f32 = 4.2857143283e-01; /* 0x3edb6db7 */ const L3: f32 = 3.3333334327e-01; /* 0x3eaaaaab */ const L4: f32 = 2.7272811532e-01; /* 0x3e8ba305 */ const L5: f32 = 2.3066075146e-01; /* 0x3e6c3255 */ const L6: f32 = 2.0697501302e-01; /* 0x3e53f142 */ const P1: f32 = 1.6666667163e-01; /* 0x3e2aaaab */ const P2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ const P3: f32 = 6.6137559770e-05; /* 0x388ab355 */ const P4: f32 = -1.6533901999e-06; /* 0xb5ddea0e */ const P5: f32 = 4.1381369442e-08; /* 0x3331bb4c */ const LG2: f32 = 6.9314718246e-01; /* 0x3f317218 */ const LG2_H: f32 = 6.93145752e-01; /* 0x3f317200 */ const LG2_L: f32 = 1.42860654e-06; /* 0x35bfbe8c */ const OVT: f32 = 4.2995665694e-08; /* -(128-log2(ovfl+.5ulp)) */ const CP: f32 = 9.6179670095e-01; /* 0x3f76384f =2/(3ln2) */ const CP_H: f32 = 9.6191406250e-01; /* 0x3f764000 =12b cp */ const CP_L: f32 = -1.1736857402e-04; /* 0xb8f623c6 =tail of cp_h */ const IVLN2: f32 = 1.4426950216e+00; const IVLN2_H: f32 = 1.4426879883e+00; const IVLN2_L: f32 = 7.0526075433e-06; /// Returns `x` to the power of `y` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn powf(x: f32, y: f32) -> f32 { let mut z: f32; let mut ax: f32; let z_h: f32; let z_l: f32; let mut p_h: f32; let mut p_l: f32; let y1: f32; let mut t1: f32; let t2: f32; let mut r: f32; let s: f32; let mut sn: f32; let mut t: f32; let mut u: f32; let mut v: f32; let mut w: f32; let i: i32; let mut j: i32; let mut k: i32; let mut yisint: i32; let mut n: i32; let hx: i32; let hy: i32; let mut ix: i32; let iy: i32; let mut is: i32; hx = x.to_bits() as i32; hy = y.to_bits() as i32; ix = hx & 0x7fffffff; iy = hy & 0x7fffffff; /* x**0 = 1, even if x is NaN */ if iy == 0 { return 1.0; } /* 1**y = 1, even if y is NaN */ if hx == 0x3f800000 { return 1.0; } /* NaN if either arg is NaN */ if ix > 0x7f800000 || iy > 0x7f800000 { return x + y; } /* determine if y is an odd int when x < 0 * yisint = 0 ... y is not an integer * yisint = 1 ... y is an odd int * yisint = 2 ... y is an even int */ yisint = 0; if hx < 0 { if iy >= 0x4b800000 { yisint = 2; /* even integer y */ } else if iy >= 0x3f800000 { k = (iy >> 23) - 0x7f; /* exponent */ j = iy >> (23 - k); if (j << (23 - k)) == iy { yisint = 2 - (j & 1); } } } /* special value of y */ if iy == 0x7f800000 { /* y is +-inf */ match ix.cmp(&0x3f800000) { /* (-1)**+-inf is 1 */ Ordering::Equal => return 1.0, /* (|x|>1)**+-inf = inf,0 */ Ordering::Greater => return if hy >= 0 { y } else { 0.0 }, /* (|x|<1)**+-inf = 0,inf */ Ordering::Less => return if hy >= 0 { 0.0 } else { -y }, } } if iy == 0x3f800000 { /* y is +-1 */ return if hy >= 0 { x } else { 1.0 / x }; } if hy == 0x40000000 { /* y is 2 */ return x * x; } if hy == 0x3f000000 /* y is 0.5 */ && hx >= 0 { /* x >= +0 */ return sqrtf(x); } ax = fabsf(x); /* special value of x */ if ix == 0x7f800000 || ix == 0 || ix == 0x3f800000 { /* x is +-0,+-inf,+-1 */ z = ax; if hy < 0 { /* z = (1/|x|) */ z = 1.0 / z; } if hx < 0 { if ((ix - 0x3f800000) | yisint) == 0 { z = (z - z) / (z - z); /* (-1)**non-int is NaN */ } else if yisint == 1 { z = -z; /* (x<0)**odd = -(|x|**odd) */ } } return z; } sn = 1.0; /* sign of result */ if hx < 0 { if yisint == 0 { /* (x<0)**(non-int) is NaN */ return (x - x) / (x - x); } if yisint == 1 { /* (x<0)**(odd int) */ sn = -1.0; } } /* |y| is HUGE */ if iy > 0x4d000000 { /* if |y| > 2**27 */ /* over/underflow if x is not close to one */ if ix < 0x3f7ffff8 { return if hy < 0 { sn * HUGE * HUGE } else { sn * TINY * TINY }; } if ix > 0x3f800007 { return if hy > 0 { sn * HUGE * HUGE } else { sn * TINY * TINY }; } /* now |1-x| is TINY <= 2**-20, suffice to compute log(x) by x-x^2/2+x^3/3-x^4/4 */ t = ax - 1.; /* t has 20 trailing zeros */ w = (t * t) * (0.5 - t * (0.333333333333 - t * 0.25)); u = IVLN2_H * t; /* IVLN2_H has 16 sig. bits */ v = t * IVLN2_L - w * IVLN2; t1 = u + v; is = t1.to_bits() as i32; t1 = f32::from_bits(is as u32 & 0xfffff000); t2 = v - (t1 - u); } else { let mut s2: f32; let mut s_h: f32; let s_l: f32; let mut t_h: f32; let mut t_l: f32; n = 0; /* take care subnormal number */ if ix < 0x00800000 { ax *= TWO24; n -= 24; ix = ax.to_bits() as i32; } n += ((ix) >> 23) - 0x7f; j = ix & 0x007fffff; /* determine interval */ ix = j | 0x3f800000; /* normalize ix */ if j <= 0x1cc471 { /* |x|> 1) & 0xfffff000) | 0x20000000) as i32; t_h = f32::from_bits(is as u32 + 0x00400000 + ((k as u32) << 21)); t_l = ax - (t_h - i!(BP, k as usize)); s_l = v * ((u - s_h * t_h) - s_h * t_l); /* compute log(ax) */ s2 = s * s; r = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); r += s_l * (s_h + s); s2 = s_h * s_h; t_h = 3.0 + s2 + r; is = t_h.to_bits() as i32; t_h = f32::from_bits(is as u32 & 0xfffff000); t_l = r - ((t_h - 3.0) - s2); /* u+v = s*(1+...) */ u = s_h * t_h; v = s_l * t_h + t_l * s; /* 2/(3log2)*(s+...) */ p_h = u + v; is = p_h.to_bits() as i32; p_h = f32::from_bits(is as u32 & 0xfffff000); p_l = v - (p_h - u); z_h = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ z_l = CP_L * p_h + p_l * CP + i!(DP_L, k as usize); /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */ t = n as f32; t1 = ((z_h + z_l) + i!(DP_H, k as usize)) + t; is = t1.to_bits() as i32; t1 = f32::from_bits(is as u32 & 0xfffff000); t2 = z_l - (((t1 - t) - i!(DP_H, k as usize)) - z_h); }; /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ is = y.to_bits() as i32; y1 = f32::from_bits(is as u32 & 0xfffff000); p_l = (y - y1) * t1 + y * t2; p_h = y1 * t1; z = p_l + p_h; j = z.to_bits() as i32; if j > 0x43000000 { /* if z > 128 */ return sn * HUGE * HUGE; /* overflow */ } else if j == 0x43000000 { /* if z == 128 */ if p_l + OVT > z - p_h { return sn * HUGE * HUGE; /* overflow */ } } else if (j & 0x7fffffff) > 0x43160000 { /* z < -150 */ // FIXME: check should be (uint32_t)j > 0xc3160000 return sn * TINY * TINY; /* underflow */ } else if j as u32 == 0xc3160000 /* z == -150 */ && p_l <= z - p_h { return sn * TINY * TINY; /* underflow */ } /* * compute 2**(p_h+p_l) */ i = j & 0x7fffffff; k = (i >> 23) - 0x7f; n = 0; if i > 0x3f000000 { /* if |z| > 0.5, set n = [z+0.5] */ n = j + (0x00800000 >> (k + 1)); k = ((n & 0x7fffffff) >> 23) - 0x7f; /* new k for n */ t = f32::from_bits(n as u32 & !(0x007fffff >> k)); n = ((n & 0x007fffff) | 0x00800000) >> (23 - k); if j < 0 { n = -n; } p_h -= t; } t = p_l + p_h; is = t.to_bits() as i32; t = f32::from_bits(is as u32 & 0xffff8000); u = t * LG2_H; v = (p_l - (t - p_h)) * LG2 + t * LG2_L; z = u + v; w = v - (z - u); t = z * z; t1 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); r = (z * t1) / (t1 - 2.0) - (w + z * w); z = 1.0 - (r - z); j = z.to_bits() as i32; j += n << 23; if (j >> 23) <= 0 { /* subnormal output */ z = scalbnf(z, n); } else { z = f32::from_bits(j as u32); } sn * z } libm-0.2.15/src/math/rem_pio2.rs000064400000000000000000000167131046102023000144460ustar 00000000000000// origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2.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. // ==================================================== // // Optimized by Bruce D. Evans. */ use super::rem_pio2_large; // #if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 // #define EPS DBL_EPSILON const EPS: f64 = 2.2204460492503131e-16; // #elif FLT_EVAL_METHOD==2 // #define EPS LDBL_EPSILON // #endif // TODO: Support FLT_EVAL_METHOD? const TO_INT: f64 = 1.5 / EPS; /// 53 bits of 2/pi const INV_PIO2: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ /// first 33 bits of pi/2 const PIO2_1: f64 = 1.57079632673412561417e+00; /* 0x3FF921FB, 0x54400000 */ /// pi/2 - PIO2_1 const PIO2_1T: f64 = 6.07710050650619224932e-11; /* 0x3DD0B461, 0x1A626331 */ /// second 33 bits of pi/2 const PIO2_2: f64 = 6.07710050630396597660e-11; /* 0x3DD0B461, 0x1A600000 */ /// pi/2 - (PIO2_1+PIO2_2) const PIO2_2T: f64 = 2.02226624879595063154e-21; /* 0x3BA3198A, 0x2E037073 */ /// third 33 bits of pi/2 const PIO2_3: f64 = 2.02226624871116645580e-21; /* 0x3BA3198A, 0x2E000000 */ /// pi/2 - (PIO2_1+PIO2_2+PIO2_3) const PIO2_3T: f64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ // return the remainder of x rem pi/2 in y[0]+y[1] // use rem_pio2_large() for large x // // caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { let x1p24 = f64::from_bits(0x4170000000000000); let sign = (f64::to_bits(x) >> 63) as i32; let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; fn medium(x: f64, ix: u32) -> (i32, f64, f64) { /* rint(x/(pi/2)), Assume round-to-nearest. */ let tmp = x * INV_PIO2 + TO_INT; // force rounding of tmp to it's storage format on x87 to avoid // excess precision issues. #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] let tmp = force_eval!(tmp); let f_n = tmp - TO_INT; let n = f_n as i32; let mut r = x - f_n * PIO2_1; let mut w = f_n * PIO2_1T; /* 1st round, good to 85 bits */ let mut y0 = r - w; let ui = f64::to_bits(y0); let ey = (ui >> 52) as i32 & 0x7ff; let ex = (ix >> 20) as i32; if ex - ey > 16 { /* 2nd round, good to 118 bits */ let t = r; w = f_n * PIO2_2; r = t - w; w = f_n * PIO2_2T - ((t - r) - w); y0 = r - w; let ey = (f64::to_bits(y0) >> 52) as i32 & 0x7ff; if ex - ey > 49 { /* 3rd round, good to 151 bits, covers all cases */ let t = r; w = f_n * PIO2_3; r = t - w; w = f_n * PIO2_3T - ((t - r) - w); y0 = r - w; } } let y1 = (r - y0) - w; (n, y0, y1) } if ix <= 0x400f6a7a { /* |x| ~<= 5pi/4 */ if (ix & 0xfffff) == 0x921fb { /* |x| ~= pi/2 or 2pi/2 */ return medium(x, ix); /* cancellation -- use medium case */ } if ix <= 0x4002d97c { /* |x| ~<= 3pi/4 */ if sign == 0 { let z = x - PIO2_1; /* one round good to 85 bits */ let y0 = z - PIO2_1T; let y1 = (z - y0) - PIO2_1T; return (1, y0, y1); } else { let z = x + PIO2_1; let y0 = z + PIO2_1T; let y1 = (z - y0) + PIO2_1T; return (-1, y0, y1); } } else if sign == 0 { let z = x - 2.0 * PIO2_1; let y0 = z - 2.0 * PIO2_1T; let y1 = (z - y0) - 2.0 * PIO2_1T; return (2, y0, y1); } else { let z = x + 2.0 * PIO2_1; let y0 = z + 2.0 * PIO2_1T; let y1 = (z - y0) + 2.0 * PIO2_1T; return (-2, y0, y1); } } if ix <= 0x401c463b { /* |x| ~<= 9pi/4 */ if ix <= 0x4015fdbc { /* |x| ~<= 7pi/4 */ if ix == 0x4012d97c { /* |x| ~= 3pi/2 */ return medium(x, ix); } if sign == 0 { let z = x - 3.0 * PIO2_1; let y0 = z - 3.0 * PIO2_1T; let y1 = (z - y0) - 3.0 * PIO2_1T; return (3, y0, y1); } else { let z = x + 3.0 * PIO2_1; let y0 = z + 3.0 * PIO2_1T; let y1 = (z - y0) + 3.0 * PIO2_1T; return (-3, y0, y1); } } else { if ix == 0x401921fb { /* |x| ~= 4pi/2 */ return medium(x, ix); } if sign == 0 { let z = x - 4.0 * PIO2_1; let y0 = z - 4.0 * PIO2_1T; let y1 = (z - y0) - 4.0 * PIO2_1T; return (4, y0, y1); } else { let z = x + 4.0 * PIO2_1; let y0 = z + 4.0 * PIO2_1T; let y1 = (z - y0) + 4.0 * PIO2_1T; return (-4, y0, y1); } } } if ix < 0x413921fb { /* |x| ~< 2^20*(pi/2), medium size */ return medium(x, ix); } /* * all other (large) arguments */ if ix >= 0x7ff00000 { /* x is inf or NaN */ let y0 = x - x; let y1 = y0; return (0, y0, y1); } /* set z = scalbn(|x|,-ilogb(x)+23) */ let mut ui = f64::to_bits(x); ui &= (!1) >> 12; ui |= (0x3ff + 23) << 52; let mut z = f64::from_bits(ui); let mut tx = [0.0; 3]; for i in 0..2 { i!(tx,i, =, z as i32 as f64); z = (z - i!(tx, i)) * x1p24; } i!(tx,2, =, z); /* skip zero terms, first term is non-zero */ let mut i = 2; while i != 0 && i!(tx, i) == 0.0 { i -= 1; } let mut ty = [0.0; 3]; let n = rem_pio2_large(&tx[..=i], &mut ty, ((ix as i32) >> 20) - (0x3ff + 23), 1); if sign != 0 { return (-n, -i!(ty, 0), -i!(ty, 1)); } (n, i!(ty, 0), i!(ty, 1)) } #[cfg(test)] mod tests { use super::rem_pio2; #[test] // FIXME(correctness): inaccurate results on i586 #[cfg_attr(all(target_arch = "x86", not(target_feature = "sse")), ignore)] fn test_near_pi() { let arg = 3.141592025756836; let arg = force_eval!(arg); assert_eq!( rem_pio2(arg), (2, -6.278329573009626e-7, -2.1125998133974653e-23) ); let arg = 3.141592033207416; let arg = force_eval!(arg); assert_eq!( rem_pio2(arg), (2, -6.20382377148128e-7, -2.1125998133974653e-23) ); let arg = 3.141592144966125; let arg = force_eval!(arg); assert_eq!( rem_pio2(arg), (2, -5.086236681942706e-7, -2.1125998133974653e-23) ); let arg = 3.141592979431152; let arg = force_eval!(arg); assert_eq!( rem_pio2(arg), (2, 3.2584135866119817e-7, -2.1125998133974653e-23) ); } #[test] fn test_overflow_b9b847() { let _ = rem_pio2(-3054214.5490637687); } #[test] fn test_overflow_4747b9() { let _ = rem_pio2(917340800458.2274); } } libm-0.2.15/src/math/rem_pio2_large.rs000064400000000000000000000474201046102023000156170ustar 00000000000000#![allow(unused_unsafe)] /* origin: FreeBSD /usr/src/lib/msun/src/k_rem_pio2.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. * ==================================================== */ use super::{floor, scalbn}; // initial value for jk const INIT_JK: [usize; 4] = [3, 4, 4, 6]; // Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi // // integer array, contains the (24*i)-th to (24*i+23)-th // bit of 2/pi after binary point. The corresponding // floating value is // // ipio2[i] * 2^(-24(i+1)). // // NB: This table must have at least (e0-3)/24 + jk terms. // For quad precision (e0 <= 16360, jk = 6), this is 686. #[cfg(any(target_pointer_width = "32", target_pointer_width = "16"))] const IPIO2: [i32; 66] = [ 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, 0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, ]; #[cfg(target_pointer_width = "64")] const IPIO2: [i32; 690] = [ 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, 0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, 0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, 0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2, 0xDE4F98, 0x327DBB, 0xC33D26, 0xEF6B1E, 0x5EF89F, 0x3A1F35, 0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, 0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C, 0x467D86, 0x2D71E3, 0x9AC69B, 0x006233, 0x7CD2B4, 0x97A7B4, 0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, 0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7, 0xCB2324, 0x778AD6, 0x23545A, 0xB91F00, 0x1B0AF1, 0xDFCE19, 0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, 0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16, 0xDE3B58, 0x929BDE, 0x2822D2, 0xE88628, 0x4D58E2, 0x32CAC6, 0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, 0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48, 0xD36710, 0xD8DDAA, 0x425FAE, 0xCE616A, 0xA4280A, 0xB499D3, 0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, 0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55, 0x36D9CA, 0xD2A828, 0x8D61C2, 0x77C912, 0x142604, 0x9B4612, 0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, 0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC, 0xC3E7B3, 0x28F8C7, 0x940593, 0x3E71C1, 0xB3092E, 0xF3450B, 0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, 0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4, 0x9794E8, 0x84E6E2, 0x973199, 0x6BED88, 0x365F5F, 0x0EFDBB, 0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, 0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C, 0x90AA47, 0x02E774, 0x24D6BD, 0xA67DF7, 0x72486E, 0xEF169F, 0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, 0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437, 0x10D86D, 0x324832, 0x754C5B, 0xD4714E, 0x6E5445, 0xC1090B, 0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, 0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD, 0x6AE290, 0x89D988, 0x50722C, 0xBEA404, 0x940777, 0x7030F3, 0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, 0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717, 0x3BDF08, 0x2B3715, 0xA0805C, 0x93805A, 0x921110, 0xD8E80F, 0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, 0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB, 0xAA140A, 0x2F2689, 0x768364, 0x333B09, 0x1A940E, 0xAA3A51, 0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, 0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C, 0x5BC3D8, 0xC492F5, 0x4BADC6, 0xA5CA4E, 0xCD37A7, 0x36A9E6, 0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, 0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED, 0x306529, 0xBF5657, 0x3AFF47, 0xB9F96A, 0xF3BE75, 0xDF9328, 0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, 0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0, 0xA8654F, 0xA5C1D2, 0x0F3F0B, 0xCD785B, 0x76F923, 0x048B7B, 0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, 0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3, 0xDA4886, 0xA05DF7, 0xF480C6, 0x2FF0AC, 0x9AECDD, 0xBC5C3F, 0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, 0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B, 0x2A1216, 0x2DB7DC, 0xFDE5FA, 0xFEDB89, 0xFDBE89, 0x6C76E4, 0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, 0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31, 0x48D784, 0x16DF30, 0x432DC7, 0x356125, 0xCE70C9, 0xB8CB30, 0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, 0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E, 0xC4F133, 0x5F6E13, 0xE4305D, 0xA92E85, 0xC3B21D, 0x3632A1, 0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, 0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4, 0xCBDA11, 0xD0BE7D, 0xC1DB9B, 0xBD17AB, 0x81A2CA, 0x5C6A08, 0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, 0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9, 0x4F6A68, 0xA82A4A, 0x5AC44F, 0xBCF82D, 0x985AD7, 0x95C7F4, 0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, 0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C, 0xD0C0B2, 0x485551, 0x0EFB1E, 0xC37295, 0x3B06A3, 0x3540C0, 0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, 0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0, 0x3C3ABA, 0x461846, 0x5F7555, 0xF5BDD2, 0xC6926E, 0x5D2EAC, 0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, 0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893, 0x745D7C, 0xB2AD6B, 0x9D6ECD, 0x7B723E, 0x6A11C6, 0xA9CFF7, 0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, 0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F, 0xBEFDFD, 0xEF4556, 0x367ED9, 0x13D9EC, 0xB9BA8B, 0xFC97C4, 0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, 0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B, 0x9C2A3E, 0xCC5F11, 0x4A0BFD, 0xFBF4E1, 0x6D3B8E, 0x2C86E2, 0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, 0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E, 0xCC2254, 0xDC552A, 0xD6C6C0, 0x96190B, 0xB8701A, 0x649569, 0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, 0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9, 0x9B5861, 0xBC57E1, 0xC68351, 0x103ED8, 0x4871DD, 0xDD1C2D, 0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, 0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855, 0x382682, 0x9BE7CA, 0xA40D51, 0xB13399, 0x0ED7A9, 0x480569, 0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, 0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE, 0x5FD45E, 0xA4677B, 0x7AACBA, 0xA2F655, 0x23882B, 0x55BA41, 0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, 0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F, 0xAE5ADB, 0x86C547, 0x624385, 0x3B8621, 0x94792C, 0x876110, 0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, 0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365, 0xB1933D, 0x0B7CBD, 0xDC51A4, 0x63DD27, 0xDDE169, 0x19949A, 0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, 0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5, 0x4D7E6F, 0x5119A5, 0xABF9B5, 0xD6DF82, 0x61DD96, 0x023616, 0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, 0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0, ]; const PIO2: [f64; 8] = [ 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ ]; // fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) -> i32 // // Input parameters: // x[] The input value (must be positive) is broken into nx // pieces of 24-bit integers in double precision format. // x[i] will be the i-th 24 bit of x. The scaled exponent // of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 // match x's up to 24 bits. // // Example of breaking a double positive z into x[0]+x[1]+x[2]: // e0 = ilogb(z)-23 // z = scalbn(z,-e0) // for i = 0,1,2 // x[i] = floor(z) // z = (z-x[i])*2**24 // // y[] ouput result in an array of double precision numbers. // The dimension of y[] is: // 24-bit precision 1 // 53-bit precision 2 // 64-bit precision 2 // 113-bit precision 3 // The actual value is the sum of them. Thus for 113-bit // precison, one may have to do something like: // // long double t,w,r_head, r_tail; // t = (long double)y[2] + (long double)y[1]; // w = (long double)y[0]; // r_head = t+w; // r_tail = w - (r_head - t); // // e0 The exponent of x[0]. Must be <= 16360 or you need to // expand the ipio2 table. // // prec an integer indicating the precision: // 0 24 bits (single) // 1 53 bits (double) // 2 64 bits (extended) // 3 113 bits (quad) // // Here is the description of some local variables: // // jk jk+1 is the initial number of terms of ipio2[] needed // in the computation. The minimum and recommended value // for jk is 3,4,4,6 for single, double, extended, and quad. // jk+1 must be 2 larger than you might expect so that our // recomputation test works. (Up to 24 bits in the integer // part (the 24 bits of it that we compute) and 23 bits in // the fraction part may be lost to cancelation before we // recompute.) // // jz local integer variable indicating the number of // terms of ipio2[] used. // // jx nx - 1 // // jv index for pointing to the suitable ipio2[] for the // computation. In general, we want // ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 // is an integer. Thus // e0-3-24*jv >= 0 or (e0-3)/24 >= jv // Hence jv = max(0,(e0-3)/24). // // jp jp+1 is the number of terms in PIo2[] needed, jp = jk. // // q[] double array with integral value, representing the // 24-bits chunk of the product of x and 2/pi. // // q0 the corresponding exponent of q[0]. Note that the // exponent for q[i] would be q0-24*i. // // PIo2[] double precision array, obtained by cutting pi/2 // into 24 bits chunks. // // f[] ipio2[] in floating point // // iq[] integer array by breaking up q[] in 24-bits chunk. // // fq[] final product of x*(2/pi) in fq[0],..,fq[jk] // // ih integer. If >0 it indicates q[] is >= 0.5, hence // it also indicates the *sign* of the result. /// Return the last three digits of N with y = x - N*pi/2 /// so that |y| < pi/2. /// /// The method is to compute the integer (mod 8) and fraction parts of /// (2/pi)*x without doing the full multiplication. In general we /// skip the part of the product that are known to be a huge integer ( /// more accurately, = 0 mod 8 ). Thus the number of operations are /// independent of the exponent of the input. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 let x1p_24 = f64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24) if cfg!(target_pointer_width = "64") { debug_assert!(e0 <= 16360); } let nx = x.len(); let mut fw: f64; let mut n: i32; let mut ih: i32; let mut z: f64; let mut f: [f64; 20] = [0.; 20]; let mut fq: [f64; 20] = [0.; 20]; let mut q: [f64; 20] = [0.; 20]; let mut iq: [i32; 20] = [0; 20]; /* initialize jk*/ let jk = i!(INIT_JK, prec); let jp = jk; /* determine jx,jv,q0, note that 3>q0 */ let jx = nx - 1; let mut jv = div!(e0 - 3, 24); if jv < 0 { jv = 0; } let mut q0 = e0 - 24 * (jv + 1); let jv = jv as usize; /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ let mut j = (jv as i32) - (jx as i32); let m = jx + jk; for i in 0..=m { i!(f, i, =, if j < 0 { 0. } else { i!(IPIO2, j as usize) as f64 }); j += 1; } /* compute q[0],q[1],...q[jk] */ for i in 0..=jk { fw = 0f64; for j in 0..=jx { fw += i!(x, j) * i!(f, jx + i - j); } i!(q, i, =, fw); } let mut jz = jk; 'recompute: loop { /* distill q[] into iq[] reversingly */ let mut i = 0i32; z = i!(q, jz); for j in (1..=jz).rev() { fw = (x1p_24 * z) as i32 as f64; i!(iq, i as usize, =, (z - x1p24 * fw) as i32); z = i!(q, j - 1) + fw; i += 1; } /* compute n */ z = scalbn(z, q0); /* actual value of z */ z -= 8.0 * floor(z * 0.125); /* trim off integer >= 8 */ n = z as i32; z -= n as f64; ih = 0; if q0 > 0 { /* need iq[jz-1] to determine n */ i = i!(iq, jz - 1) >> (24 - q0); n += i; i!(iq, jz - 1, -=, i << (24 - q0)); ih = i!(iq, jz - 1) >> (23 - q0); } else if q0 == 0 { ih = i!(iq, jz - 1) >> 23; } else if z >= 0.5 { ih = 2; } if ih > 0 { /* q > 0.5 */ n += 1; let mut carry = 0i32; for i in 0..jz { /* compute 1-q */ let j = i!(iq, i); if carry == 0 { if j != 0 { carry = 1; i!(iq, i, =, 0x1000000 - j); } } else { i!(iq, i, =, 0xffffff - j); } } if q0 > 0 { /* rare case: chance is 1 in 12 */ match q0 { 1 => { i!(iq, jz - 1, &=, 0x7fffff); } 2 => { i!(iq, jz - 1, &=, 0x3fffff); } _ => {} } } if ih == 2 { z = 1. - z; if carry != 0 { z -= scalbn(1., q0); } } } /* check if recomputation is needed */ if z == 0. { let mut j = 0; for i in (jk..=jz - 1).rev() { j |= i!(iq, i); } if j == 0 { /* need recomputation */ let mut k = 1; while i!(iq, jk - k, ==, 0) { k += 1; /* k = no. of terms needed */ } for i in (jz + 1)..=(jz + k) { /* add q[jz+1] to q[jz+k] */ i!(f, jx + i, =, i!(IPIO2, jv + i) as f64); fw = 0f64; for j in 0..=jx { fw += i!(x, j) * i!(f, jx + i - j); } i!(q, i, =, fw); } jz += k; continue 'recompute; } } break; } /* chop off zero terms */ if z == 0. { jz -= 1; q0 -= 24; while i!(iq, jz) == 0 { jz -= 1; q0 -= 24; } } else { /* break z into 24-bit if necessary */ z = scalbn(z, -q0); if z >= x1p24 { fw = (x1p_24 * z) as i32 as f64; i!(iq, jz, =, (z - x1p24 * fw) as i32); jz += 1; q0 += 24; i!(iq, jz, =, fw as i32); } else { i!(iq, jz, =, z as i32); } } /* convert integer "bit" chunk to floating-point value */ fw = scalbn(1., q0); for i in (0..=jz).rev() { i!(q, i, =, fw * (i!(iq, i) as f64)); fw *= x1p_24; } /* compute PIo2[0,...,jp]*q[jz,...,0] */ for i in (0..=jz).rev() { fw = 0f64; let mut k = 0; while (k <= jp) && (k <= jz - i) { fw += i!(PIO2, k) * i!(q, i + k); k += 1; } i!(fq, jz - i, =, fw); } /* compress fq[] into y[] */ match prec { 0 => { fw = 0f64; for i in (0..=jz).rev() { fw += i!(fq, i); } i!(y, 0, =, if ih == 0 { fw } else { -fw }); } 1 | 2 => { fw = 0f64; for i in (0..=jz).rev() { fw += i!(fq, i); } i!(y, 0, =, if ih == 0 { fw } else { -fw }); fw = i!(fq, 0) - fw; for i in 1..=jz { fw += i!(fq, i); } i!(y, 1, =, if ih == 0 { fw } else { -fw }); } 3 => { /* painful */ for i in (1..=jz).rev() { fw = i!(fq, i - 1) + i!(fq, i); i!(fq, i, +=, i!(fq, i - 1) - fw); i!(fq, i - 1, =, fw); } for i in (2..=jz).rev() { fw = i!(fq, i - 1) + i!(fq, i); i!(fq, i, +=, i!(fq, i - 1) - fw); i!(fq, i - 1, =, fw); } fw = 0f64; for i in (2..=jz).rev() { fw += i!(fq, i); } if ih == 0 { i!(y, 0, =, i!(fq, 0)); i!(y, 1, =, i!(fq, 1)); i!(y, 2, =, fw); } else { i!(y, 0, =, -i!(fq, 0)); i!(y, 1, =, -i!(fq, 1)); i!(y, 2, =, -fw); } } #[cfg(debug_assertions)] _ => unreachable!(), #[cfg(not(debug_assertions))] _ => {} } n & 7 } libm-0.2.15/src/math/rem_pio2f.rs000064400000000000000000000044231046102023000146070ustar 00000000000000/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2f.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. * ==================================================== */ use core::f64; use super::rem_pio2_large; const TOINT: f64 = 1.5 / f64::EPSILON; /// 53 bits of 2/pi const INV_PIO2: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ /// first 25 bits of pi/2 const PIO2_1: f64 = 1.57079631090164184570e+00; /* 0x3FF921FB, 0x50000000 */ /// pi/2 - pio2_1 const PIO2_1T: f64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ /// Return the remainder of x rem pi/2 in *y /// /// use double precision for everything except passing x /// use __rem_pio2_large() for large x #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn rem_pio2f(x: f32) -> (i32, f64) { let x64 = x as f64; let mut tx: [f64; 1] = [0.]; let mut ty: [f64; 1] = [0.]; let ix = x.to_bits() & 0x7fffffff; /* 25+53 bit pi is good enough for medium size */ if ix < 0x4dc90fdb { /* |x| ~< 2^28*(pi/2), medium size */ /* Use a specialized rint() to get fn. Assume round-to-nearest. */ let tmp = x64 * INV_PIO2 + TOINT; // force rounding of tmp to it's storage format on x87 to avoid // excess precision issues. #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] let tmp = force_eval!(tmp); let f_n = tmp - TOINT; return (f_n as i32, x64 - f_n * PIO2_1 - f_n * PIO2_1T); } if ix >= 0x7f800000 { /* x is inf or NaN */ return (0, x64 - x64); } /* scale x into [2^23, 2^24-1] */ let sign = (x.to_bits() >> 31) != 0; let e0 = ((ix >> 23) - (0x7f + 23)) as i32; /* e0 = ilogb(|x|)-23, positive */ tx[0] = f32::from_bits(ix - (e0 << 23) as u32) as f64; let n = rem_pio2_large(&tx, &mut ty, e0, 0); if sign { return (-n, -ty[0]); } (n, ty[0]) } libm-0.2.15/src/math/remainder.rs000064400000000000000000000002361046102023000146710ustar 00000000000000#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn remainder(x: f64, y: f64) -> f64 { let (result, _) = super::remquo(x, y); result } libm-0.2.15/src/math/remainderf.rs000064400000000000000000000002401046102023000150320ustar 00000000000000#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn remainderf(x: f32, y: f32) -> f32 { let (result, _) = super::remquof(x, y); result } libm-0.2.15/src/math/remquo.rs000064400000000000000000000046061046102023000142400ustar 00000000000000#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn remquo(mut x: f64, mut y: f64) -> (f64, i32) { let ux: u64 = x.to_bits(); let mut uy: u64 = y.to_bits(); let mut ex = ((ux >> 52) & 0x7ff) as i32; let mut ey = ((uy >> 52) & 0x7ff) as i32; let sx = (ux >> 63) != 0; let sy = (uy >> 63) != 0; let mut q: u32; let mut i: u64; let mut uxi: u64 = ux; if (uy << 1) == 0 || y.is_nan() || ex == 0x7ff { return ((x * y) / (x * y), 0); } if (ux << 1) == 0 { return (x, 0); } /* normalize x and y */ if ex == 0 { i = uxi << 12; while (i >> 63) == 0 { ex -= 1; i <<= 1; } uxi <<= -ex + 1; } else { uxi &= (!0) >> 12; uxi |= 1 << 52; } if ey == 0 { i = uy << 12; while (i >> 63) == 0 { ey -= 1; i <<= 1; } uy <<= -ey + 1; } else { uy &= (!0) >> 12; uy |= 1 << 52; } q = 0; if ex + 1 != ey { if ex < ey { return (x, 0); } /* x mod y */ while ex > ey { i = uxi.wrapping_sub(uy); if (i >> 63) == 0 { uxi = i; q += 1; } uxi <<= 1; q <<= 1; ex -= 1; } i = uxi.wrapping_sub(uy); if (i >> 63) == 0 { uxi = i; q += 1; } if uxi == 0 { ex = -60; } else { while (uxi >> 52) == 0 { uxi <<= 1; ex -= 1; } } } /* scale result and decide between |x| and |x|-|y| */ if ex > 0 { uxi -= 1 << 52; uxi |= (ex as u64) << 52; } else { uxi >>= -ex + 1; } x = f64::from_bits(uxi); if sy { y = -y; } if ex == ey || (ex + 1 == ey && (2.0 * x > y || (2.0 * x == y && (q % 2) != 0))) { x -= y; // TODO: this matches musl behavior, but it is incorrect q = q.wrapping_add(1); } q &= 0x7fffffff; let quo = if sx ^ sy { -(q as i32) } else { q as i32 }; if sx { (-x, quo) } else { (x, quo) } } #[cfg(test)] mod tests { use super::remquo; #[test] fn test_q_overflow() { // 0xc000000000000001, 0x04c0000000000004 let _ = remquo(-2.0000000000000004, 8.406091369059082e-286); } } libm-0.2.15/src/math/remquof.rs000064400000000000000000000041271046102023000144040ustar 00000000000000#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn remquof(mut x: f32, mut y: f32) -> (f32, i32) { let ux: u32 = x.to_bits(); let mut uy: u32 = y.to_bits(); let mut ex = ((ux >> 23) & 0xff) as i32; let mut ey = ((uy >> 23) & 0xff) as i32; let sx = (ux >> 31) != 0; let sy = (uy >> 31) != 0; let mut q: u32; let mut i: u32; let mut uxi: u32 = ux; if (uy << 1) == 0 || y.is_nan() || ex == 0xff { return ((x * y) / (x * y), 0); } if (ux << 1) == 0 { return (x, 0); } /* normalize x and y */ if ex == 0 { i = uxi << 9; while (i >> 31) == 0 { ex -= 1; i <<= 1; } uxi <<= -ex + 1; } else { uxi &= (!0) >> 9; uxi |= 1 << 23; } if ey == 0 { i = uy << 9; while (i >> 31) == 0 { ey -= 1; i <<= 1; } uy <<= -ey + 1; } else { uy &= (!0) >> 9; uy |= 1 << 23; } q = 0; if ex + 1 != ey { if ex < ey { return (x, 0); } /* x mod y */ while ex > ey { i = uxi.wrapping_sub(uy); if (i >> 31) == 0 { uxi = i; q += 1; } uxi <<= 1; q <<= 1; ex -= 1; } i = uxi.wrapping_sub(uy); if (i >> 31) == 0 { uxi = i; q += 1; } if uxi == 0 { ex = -30; } else { while (uxi >> 23) == 0 { uxi <<= 1; ex -= 1; } } } /* scale result and decide between |x| and |x|-|y| */ if ex > 0 { uxi -= 1 << 23; uxi |= (ex as u32) << 23; } else { uxi >>= -ex + 1; } x = f32::from_bits(uxi); if sy { y = -y; } if ex == ey || (ex + 1 == ey && (2.0 * x > y || (2.0 * x == y && (q % 2) != 0))) { x -= y; q += 1; } q &= 0x7fffffff; let quo = if sx ^ sy { -(q as i32) } else { q as i32 }; if sx { (-x, quo) } else { (x, quo) } } libm-0.2.15/src/math/rint.rs000064400000000000000000000030061046102023000136750ustar 00000000000000use super::support::Round; /// Round `x` to the nearest integer, breaking ties toward even. #[cfg(f16_enabled)] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn rintf16(x: f16) -> f16 { select_implementation! { name: rintf16, use_arch: all(target_arch = "aarch64", target_feature = "fp16"), args: x, } super::generic::rint_round(x, Round::Nearest).val } /// Round `x` to the nearest integer, breaking ties toward even. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn rintf(x: f32) -> f32 { select_implementation! { name: rintf, use_arch: any( all(target_arch = "aarch64", target_feature = "neon"), all(target_arch = "wasm32", intrinsics_enabled), ), args: x, } super::generic::rint_round(x, Round::Nearest).val } /// Round `x` to the nearest integer, breaking ties toward even. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn rint(x: f64) -> f64 { select_implementation! { name: rint, use_arch: any( all(target_arch = "aarch64", target_feature = "neon"), all(target_arch = "wasm32", intrinsics_enabled), ), args: x, } super::generic::rint_round(x, Round::Nearest).val } /// Round `x` to the nearest integer, breaking ties toward even. #[cfg(f128_enabled)] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn rintf128(x: f128) -> f128 { super::generic::rint_round(x, Round::Nearest).val } libm-0.2.15/src/math/round.rs000064400000000000000000000014521046102023000140530ustar 00000000000000/// Round `x` to the nearest integer, breaking ties away from zero. #[cfg(f16_enabled)] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn roundf16(x: f16) -> f16 { super::generic::round(x) } /// Round `x` to the nearest integer, breaking ties away from zero. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn roundf(x: f32) -> f32 { super::generic::round(x) } /// Round `x` to the nearest integer, breaking ties away from zero. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn round(x: f64) -> f64 { super::generic::round(x) } /// Round `x` to the nearest integer, breaking ties away from zero. #[cfg(f128_enabled)] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn roundf128(x: f128) -> f128 { super::generic::round(x) } libm-0.2.15/src/math/roundeven.rs000064400000000000000000000021571046102023000147340ustar 00000000000000use super::support::{Float, Round}; /// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 /// `roundToIntegralTiesToEven`. #[cfg(f16_enabled)] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn roundevenf16(x: f16) -> f16 { roundeven_impl(x) } /// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 /// `roundToIntegralTiesToEven`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn roundevenf(x: f32) -> f32 { roundeven_impl(x) } /// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 /// `roundToIntegralTiesToEven`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn roundeven(x: f64) -> f64 { roundeven_impl(x) } /// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 /// `roundToIntegralTiesToEven`. #[cfg(f128_enabled)] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn roundevenf128(x: f128) -> f128 { roundeven_impl(x) } #[inline] pub fn roundeven_impl(x: F) -> F { super::generic::rint_round(x, Round::Nearest).val } libm-0.2.15/src/math/roundf.rs000064400000000000000000000002761046102023000142240ustar 00000000000000/// Round `x` to the nearest integer, breaking ties away from zero. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn roundf(x: f32) -> f32 { super::generic::round(x) } libm-0.2.15/src/math/roundf128.rs000064400000000000000000000003031046102023000144460ustar 00000000000000/// Round `x` to the nearest integer, breaking ties away from zero. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn roundf128(x: f128) -> f128 { super::generic::round(x) } libm-0.2.15/src/math/roundf16.rs000064400000000000000000000003001046102023000143570ustar 00000000000000/// Round `x` to the nearest integer, breaking ties away from zero. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn roundf16(x: f16) -> f16 { super::generic::round(x) } libm-0.2.15/src/math/scalbn.rs000064400000000000000000000047471046102023000142000ustar 00000000000000#[cfg(f16_enabled)] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn scalbnf16(x: f16, n: i32) -> f16 { super::generic::scalbn(x, n) } #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn scalbnf(x: f32, n: i32) -> f32 { super::generic::scalbn(x, n) } #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn scalbn(x: f64, n: i32) -> f64 { super::generic::scalbn(x, n) } #[cfg(f128_enabled)] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn scalbnf128(x: f128, n: i32) -> f128 { super::generic::scalbn(x, n) } #[cfg(test)] mod tests { use super::*; use crate::support::{CastFrom, CastInto, Float}; // Tests against N3220 fn spec_test(f: impl Fn(F, i32) -> F) where u32: CastInto, F::Int: CastFrom, F::Int: CastFrom, { // `scalbn(±0, n)` returns `±0`. assert_biteq!(f(F::NEG_ZERO, 10), F::NEG_ZERO); assert_biteq!(f(F::NEG_ZERO, 0), F::NEG_ZERO); assert_biteq!(f(F::NEG_ZERO, -10), F::NEG_ZERO); assert_biteq!(f(F::ZERO, 10), F::ZERO); assert_biteq!(f(F::ZERO, 0), F::ZERO); assert_biteq!(f(F::ZERO, -10), F::ZERO); // `scalbn(x, 0)` returns `x`. assert_biteq!(f(F::MIN, 0), F::MIN); assert_biteq!(f(F::MAX, 0), F::MAX); assert_biteq!(f(F::INFINITY, 0), F::INFINITY); assert_biteq!(f(F::NEG_INFINITY, 0), F::NEG_INFINITY); assert_biteq!(f(F::ZERO, 0), F::ZERO); assert_biteq!(f(F::NEG_ZERO, 0), F::NEG_ZERO); // `scalbn(±∞, n)` returns `±∞`. assert_biteq!(f(F::INFINITY, 10), F::INFINITY); assert_biteq!(f(F::INFINITY, -10), F::INFINITY); assert_biteq!(f(F::NEG_INFINITY, 10), F::NEG_INFINITY); assert_biteq!(f(F::NEG_INFINITY, -10), F::NEG_INFINITY); // NaN should remain NaNs. assert!(f(F::NAN, 10).is_nan()); assert!(f(F::NAN, 0).is_nan()); assert!(f(F::NAN, -10).is_nan()); assert!(f(-F::NAN, 10).is_nan()); assert!(f(-F::NAN, 0).is_nan()); assert!(f(-F::NAN, -10).is_nan()); } #[test] #[cfg(f16_enabled)] fn spec_test_f16() { spec_test::(scalbnf16); } #[test] fn spec_test_f32() { spec_test::(scalbnf); } #[test] fn spec_test_f64() { spec_test::(scalbn); } #[test] #[cfg(f128_enabled)] fn spec_test_f128() { spec_test::(scalbnf128); } } libm-0.2.15/src/math/scalbnf.rs000064400000000000000000000002071046102023000143310ustar 00000000000000#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn scalbnf(x: f32, n: i32) -> f32 { super::generic::scalbn(x, n) } libm-0.2.15/src/math/scalbnf128.rs000064400000000000000000000002141046102023000145620ustar 00000000000000#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn scalbnf128(x: f128, n: i32) -> f128 { super::generic::scalbn(x, n) } libm-0.2.15/src/math/scalbnf16.rs000064400000000000000000000002111046102023000144730ustar 00000000000000#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn scalbnf16(x: f16, n: i32) -> f16 { super::generic::scalbn(x, n) } libm-0.2.15/src/math/sin.rs000064400000000000000000000055111046102023000135150ustar 00000000000000// origin: FreeBSD /usr/src/lib/msun/src/s_sin.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}; // sin(x) // Return sine function of x. // // kernel function: // k_sin ... sine function on [-pi/4,pi/4] // k_cos ... cose 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 sine of `x` (f64). /// /// `x` is specified in radians. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sin(x: f64) -> f64 { let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 /* High word of x. */ let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; /* |x| ~< pi/4 */ if ix <= 0x3fe921fb { if ix < 0x3e500000 { /* |x| < 2**-26 */ /* raise inexact if x != 0 and underflow if subnormal*/ if ix < 0x00100000 { force_eval!(x / x1p120); } else { force_eval!(x + x1p120); } return x; } return k_sin(x, 0.0, 0); } /* sin(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_sin(y0, y1, 1), 1 => k_cos(y0, y1), 2 => -k_sin(y0, y1, 1), _ => -k_cos(y0, y1), } } #[cfg(test)] mod tests { use super::*; #[test] #[cfg_attr(x86_no_sse, ignore = "FIXME(i586): possible incorrect rounding")] fn test_near_pi() { let x = f64::from_bits(0x400921fb000FD5DD); // 3.141592026217707 let sx = f64::from_bits(0x3ea50d15ced1a4a2); // 6.273720864039205e-7 assert_eq!(sin(x), sx); } } libm-0.2.15/src/math/sincos.rs000064400000000000000000000071521046102023000142250ustar 00000000000000/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.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::{get_high_word, k_cos, k_sin, rem_pio2}; /// Both the sine and cosine of `x` (f64). /// /// `x` is specified in radians and the return value is (sin(x), cos(x)). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sincos(x: f64) -> (f64, f64) { let s: f64; let c: f64; let mut ix: u32; ix = get_high_word(x); ix &= 0x7fffffff; /* |x| ~< pi/4 */ if ix <= 0x3fe921fb { /* if |x| < 2**-27 * sqrt(2) */ if ix < 0x3e46a09e { /* raise inexact if x!=0 and underflow if subnormal */ let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120 == 2^120 if ix < 0x00100000 { force_eval!(x / x1p120); } else { force_eval!(x + x1p120); } return (x, 1.0); } return (k_sin(x, 0.0, 0), k_cos(x, 0.0)); } /* sincos(Inf or NaN) is NaN */ if ix >= 0x7ff00000 { let rv = x - x; return (rv, rv); } /* argument reduction needed */ let (n, y0, y1) = rem_pio2(x); s = k_sin(y0, y1, 1); c = k_cos(y0, y1); match n & 3 { 0 => (s, c), 1 => (c, -s), 2 => (-s, -c), 3 => (-c, s), #[cfg(debug_assertions)] _ => unreachable!(), #[cfg(not(debug_assertions))] _ => (0.0, 1.0), } } // These tests are based on those from sincosf.rs #[cfg(test)] mod tests { use super::sincos; const TOLERANCE: f64 = 1e-6; #[test] fn with_pi() { let (s, c) = sincos(core::f64::consts::PI); assert!( (s - 0.0).abs() < TOLERANCE, "|{} - {}| = {} >= {}", s, 0.0, (s - 0.0).abs(), TOLERANCE ); assert!( (c + 1.0).abs() < TOLERANCE, "|{} + {}| = {} >= {}", c, 1.0, (s + 1.0).abs(), TOLERANCE ); } #[test] fn rotational_symmetry() { use core::f64::consts::PI; const N: usize = 24; for n in 0..N { let theta = 2. * PI * (n as f64) / (N as f64); let (s, c) = sincos(theta); let (s_plus, c_plus) = sincos(theta + 2. * PI); let (s_minus, c_minus) = sincos(theta - 2. * PI); assert!( (s - s_plus).abs() < TOLERANCE, "|{} - {}| = {} >= {}", s, s_plus, (s - s_plus).abs(), TOLERANCE ); assert!( (s - s_minus).abs() < TOLERANCE, "|{} - {}| = {} >= {}", s, s_minus, (s - s_minus).abs(), TOLERANCE ); assert!( (c - c_plus).abs() < TOLERANCE, "|{} - {}| = {} >= {}", c, c_plus, (c - c_plus).abs(), TOLERANCE ); assert!( (c - c_minus).abs() < TOLERANCE, "|{} - {}| = {} >= {}", c, c_minus, (c - c_minus).abs(), TOLERANCE ); } } } libm-0.2.15/src/math/sincosf.rs000064400000000000000000000117521046102023000143740ustar 00000000000000/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.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 super::{k_cosf, k_sinf, rem_pio2f}; /* Small multiples of pi/2 rounded to double precision. */ const PI_2: f64 = 0.5 * 3.1415926535897931160E+00; const S1PIO2: f64 = 1.0 * PI_2; /* 0x3FF921FB, 0x54442D18 */ const S2PIO2: f64 = 2.0 * PI_2; /* 0x400921FB, 0x54442D18 */ const S3PIO2: f64 = 3.0 * PI_2; /* 0x4012D97C, 0x7F3321D2 */ const S4PIO2: f64 = 4.0 * PI_2; /* 0x401921FB, 0x54442D18 */ /// Both the sine and cosine of `x` (f32). /// /// `x` is specified in radians and the return value is (sin(x), cos(x)). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sincosf(x: f32) -> (f32, f32) { let s: f32; let c: f32; let mut ix: u32; let sign: bool; ix = x.to_bits(); sign = (ix >> 31) != 0; ix &= 0x7fffffff; /* |x| ~<= pi/4 */ if ix <= 0x3f490fda { /* |x| < 2**-12 */ if ix < 0x39800000 { /* raise inexact if x!=0 and underflow if subnormal */ let x1p120 = f32::from_bits(0x7b800000); // 0x1p120 == 2^120 if ix < 0x00100000 { force_eval!(x / x1p120); } else { force_eval!(x + x1p120); } return (x, 1.0); } return (k_sinf(x as f64), k_cosf(x as f64)); } /* |x| ~<= 5*pi/4 */ if ix <= 0x407b53d1 { if ix <= 0x4016cbe3 { /* |x| ~<= 3pi/4 */ if sign { s = -k_cosf(x as f64 + S1PIO2); c = k_sinf(x as f64 + S1PIO2); } else { s = k_cosf(S1PIO2 - x as f64); c = k_sinf(S1PIO2 - x as f64); } } /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ else if sign { s = -k_sinf(x as f64 + S2PIO2); c = -k_cosf(x as f64 + S2PIO2); } else { s = -k_sinf(x as f64 - S2PIO2); c = -k_cosf(x as f64 - S2PIO2); } return (s, c); } /* |x| ~<= 9*pi/4 */ if ix <= 0x40e231d5 { if ix <= 0x40afeddf { /* |x| ~<= 7*pi/4 */ if sign { s = k_cosf(x as f64 + S3PIO2); c = -k_sinf(x as f64 + S3PIO2); } else { s = -k_cosf(x as f64 - S3PIO2); c = k_sinf(x as f64 - S3PIO2); } } else if sign { s = k_sinf(x as f64 + S4PIO2); c = k_cosf(x as f64 + S4PIO2); } else { s = k_sinf(x as f64 - S4PIO2); c = k_cosf(x as f64 - S4PIO2); } return (s, c); } /* sin(Inf or NaN) is NaN */ if ix >= 0x7f800000 { let rv = x - x; return (rv, rv); } /* general argument reduction needed */ let (n, y) = rem_pio2f(x); s = k_sinf(y); c = k_cosf(y); match n & 3 { 0 => (s, c), 1 => (c, -s), 2 => (-s, -c), 3 => (-c, s), #[cfg(debug_assertions)] _ => unreachable!(), #[cfg(not(debug_assertions))] _ => (0.0, 1.0), } } // 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::sincosf; #[test] fn rotational_symmetry() { use core::f32::consts::PI; const N: usize = 24; for n in 0..N { let theta = 2. * PI * (n as f32) / (N as f32); let (s, c) = sincosf(theta); let (s_plus, c_plus) = sincosf(theta + 2. * PI); let (s_minus, c_minus) = sincosf(theta - 2. * PI); const TOLERANCE: f32 = 1e-6; assert!( (s - s_plus).abs() < TOLERANCE, "|{} - {}| = {} >= {}", s, s_plus, (s - s_plus).abs(), TOLERANCE ); assert!( (s - s_minus).abs() < TOLERANCE, "|{} - {}| = {} >= {}", s, s_minus, (s - s_minus).abs(), TOLERANCE ); assert!( (c - c_plus).abs() < TOLERANCE, "|{} - {}| = {} >= {}", c, c_plus, (c - c_plus).abs(), TOLERANCE ); assert!( (c - c_minus).abs() < TOLERANCE, "|{} - {}| = {} >= {}", c, c_minus, (c - c_minus).abs(), TOLERANCE ); } } } libm-0.2.15/src/math/sinf.rs000064400000000000000000000052271046102023000136670ustar 00000000000000/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.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 S1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ const S2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ const S3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ const S4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ /// The sine of `x` (f32). /// /// `x` is specified in radians. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sinf(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 and underflow if subnormal */ force_eval!(if ix < 0x00800000 { x / x1p120 } else { x + x1p120 }); return x; } return k_sinf(x64); } if ix <= 0x407b53d1 { /* |x| ~<= 5*pi/4 */ if ix <= 0x4016cbe3 { /* |x| ~<= 3pi/4 */ if sign { return -k_cosf(x64 + S1_PIO2); } else { return k_cosf(x64 - S1_PIO2); } } return k_sinf(if sign { -(x64 + S2_PIO2) } else { -(x64 - S2_PIO2) }); } if ix <= 0x40e231d5 { /* |x| ~<= 9*pi/4 */ if ix <= 0x40afeddf { /* |x| ~<= 7*pi/4 */ if sign { return k_cosf(x64 + S3_PIO2); } else { return -k_cosf(x64 - S3_PIO2); } } return k_sinf(if sign { x64 + S4_PIO2 } else { x64 - S4_PIO2 }); } /* sin(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_sinf(y), 1 => k_cosf(y), 2 => k_sinf(-y), _ => -k_cosf(y), } } libm-0.2.15/src/math/sinh.rs000064400000000000000000000024241046102023000136650ustar 00000000000000use super::{expm1, expo2}; // sinh(x) = (exp(x) - 1/exp(x))/2 // = (exp(x)-1 + (exp(x)-1)/exp(x))/2 // = x + x^3/6 + o(x^5) // /// The hyperbolic sine of `x` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sinh(x: f64) -> f64 { // union {double f; uint64_t i;} u = {.f = x}; // uint32_t w; // double t, h, absx; let mut uf: f64 = x; let mut ui: u64 = f64::to_bits(uf); let w: u32; let t: f64; let mut h: f64; let absx: f64; h = 0.5; if ui >> 63 != 0 { h = -h; } /* |x| */ ui &= !1 / 2; uf = f64::from_bits(ui); absx = uf; w = (ui >> 32) as u32; /* |x| < log(DBL_MAX) */ if w < 0x40862e42 { t = expm1(absx); if w < 0x3ff00000 { if w < 0x3ff00000 - (26 << 20) { /* note: inexact and underflow are raised by expm1 */ /* note: this branch avoids spurious underflow */ return x; } return h * (2.0 * t - t * t / (t + 1.0)); } /* note: |x|>log(0x1p26)+eps could be just h*exp(x) */ return h * (t + t / (t + 1.0)); } /* |x| > log(DBL_MAX) or nan */ /* note: the result is stored to handle overflow */ t = 2.0 * h * expo2(absx); t } libm-0.2.15/src/math/sinhf.rs000064400000000000000000000013221046102023000140270ustar 00000000000000use super::{expm1f, k_expo2f}; /// The hyperbolic sine of `x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sinhf(x: f32) -> f32 { let mut h = 0.5f32; let mut ix = x.to_bits(); if (ix >> 31) != 0 { h = -h; } /* |x| */ ix &= 0x7fffffff; let absx = f32::from_bits(ix); let w = ix; /* |x| < log(FLT_MAX) */ if w < 0x42b17217 { let t = expm1f(absx); if w < 0x3f800000 { if w < (0x3f800000 - (12 << 23)) { return x; } return h * (2. * t - t * t / (t + 1.)); } return h * (t + t / (t + 1.)); } /* |x| > logf(FLT_MAX) or nan */ 2. * h * k_expo2f(absx) } libm-0.2.15/src/math/sqrt.rs000064400000000000000000000025371046102023000137220ustar 00000000000000/// The square root of `x` (f16). #[cfg(f16_enabled)] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrtf16(x: f16) -> f16 { select_implementation! { name: sqrtf16, use_arch: all(target_arch = "aarch64", target_feature = "fp16"), args: x, } return super::generic::sqrt(x); } /// The square root of `x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrtf(x: f32) -> f32 { select_implementation! { name: sqrtf, use_arch: any( all(target_arch = "aarch64", target_feature = "neon"), all(target_arch = "wasm32", intrinsics_enabled), target_feature = "sse2" ), args: x, } super::generic::sqrt(x) } /// The square root of `x` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrt(x: f64) -> f64 { select_implementation! { name: sqrt, use_arch: any( all(target_arch = "aarch64", target_feature = "neon"), all(target_arch = "wasm32", intrinsics_enabled), target_feature = "sse2" ), args: x, } super::generic::sqrt(x) } /// The square root of `x` (f128). #[cfg(f128_enabled)] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrtf128(x: f128) -> f128 { return super::generic::sqrt(x); } libm-0.2.15/src/math/sqrtf.rs000064400000000000000000000006521046102023000140640ustar 00000000000000/// The square root of `x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrtf(x: f32) -> f32 { select_implementation! { name: sqrtf, use_arch: any( all(target_arch = "aarch64", target_feature = "neon"), all(target_arch = "wasm32", intrinsics_enabled), target_feature = "sse2" ), args: x, } super::generic::sqrt(x) } libm-0.2.15/src/math/sqrtf128.rs000064400000000000000000000002501046102023000143110ustar 00000000000000/// The square root of `x` (f128). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrtf128(x: f128) -> f128 { return super::generic::sqrt(x); } libm-0.2.15/src/math/sqrtf16.rs000064400000000000000000000004711046102023000142320ustar 00000000000000/// The square root of `x` (f16). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrtf16(x: f16) -> f16 { select_implementation! { name: sqrtf16, use_arch: all(target_arch = "aarch64", target_feature = "fp16"), args: x, } return super::generic::sqrt(x); } libm-0.2.15/src/math/support/big/tests.rs000064400000000000000000000135551046102023000163520ustar 00000000000000extern crate std; use std::string::String; use std::{eprintln, format}; use super::{HInt, MinInt, i256, u256}; const LOHI_SPLIT: u128 = 0xaaaaaaaaaaaaaaaaffffffffffffffff; /// Print a `u256` as hex since we can't add format implementations fn hexu(v: u256) -> String { format!("0x{:032x}{:032x}", v.hi, v.lo) } #[test] fn widen_u128() { assert_eq!( u128::MAX.widen(), u256 { lo: u128::MAX, hi: 0 } ); assert_eq!( LOHI_SPLIT.widen(), u256 { lo: LOHI_SPLIT, hi: 0 } ); } #[test] fn widen_i128() { assert_eq!((-1i128).widen(), u256::MAX.signed()); assert_eq!( (LOHI_SPLIT as i128).widen(), i256 { lo: LOHI_SPLIT, hi: u128::MAX } ); assert_eq!((-1i128).zero_widen().unsigned(), (u128::MAX).widen()); } #[test] fn widen_mul_u128() { let tests = [ ( u128::MAX / 2, 2_u128, u256 { lo: u128::MAX - 1, hi: 0, }, ), ( u128::MAX, 2_u128, u256 { lo: u128::MAX - 1, hi: 1, }, ), ( u128::MAX, u128::MAX, u256 { lo: 1, hi: u128::MAX - 1, }, ), (0, 0, u256::ZERO), (1234u128, 0, u256::ZERO), (0, 1234, u256::ZERO), ]; let mut has_errors = false; let mut add_error = |i, a, b, expected, actual| { has_errors = true; eprintln!( "\ FAILURE ({i}): {a:#034x} * {b:#034x}\n\ expected: {}\n\ got: {}\ ", hexu(expected), hexu(actual) ); }; for (i, (a, b, exp)) in tests.iter().copied().enumerate() { let res = a.widen_mul(b); let res_z = a.zero_widen_mul(b); assert_eq!(res, res_z); if res != exp { add_error(i, a, b, exp, res); } } assert!(!has_errors); } #[test] fn not_u256() { assert_eq!(!u256::ZERO, u256::MAX); } #[test] fn shr_u256() { let only_low = [ 1, u16::MAX.into(), u32::MAX.into(), u64::MAX.into(), u128::MAX, ]; let mut has_errors = false; let mut add_error = |a, b, expected, actual| { has_errors = true; eprintln!( "\ FAILURE: {} >> {b}\n\ expected: {}\n\ actual: {}\ ", hexu(a), hexu(expected), hexu(actual), ); }; for a in only_low { for perturb in 0..10 { let a = a.saturating_add(perturb); for shift in 0..128 { let res = a.widen() >> shift; let expected = (a >> shift).widen(); if res != expected { add_error(a.widen(), shift, expected, res); } } } } let check = [ ( u256::MAX, 1, u256 { lo: u128::MAX, hi: u128::MAX >> 1, }, ), ( u256::MAX, 5, u256 { lo: u128::MAX, hi: u128::MAX >> 5, }, ), ( u256::MAX, 63, u256 { lo: u128::MAX, hi: u64::MAX as u128 | (1 << 64), }, ), ( u256::MAX, 64, u256 { lo: u128::MAX, hi: u64::MAX as u128, }, ), ( u256::MAX, 65, u256 { lo: u128::MAX, hi: (u64::MAX >> 1) as u128, }, ), ( u256::MAX, 127, u256 { lo: u128::MAX, hi: 1, }, ), ( u256::MAX, 128, u256 { lo: u128::MAX, hi: 0, }, ), ( u256::MAX, 129, u256 { lo: u128::MAX >> 1, hi: 0, }, ), ( u256::MAX, 191, u256 { lo: u64::MAX as u128 | 1 << 64, hi: 0, }, ), ( u256::MAX, 192, u256 { lo: u64::MAX as u128, hi: 0, }, ), ( u256::MAX, 193, u256 { lo: u64::MAX as u128 >> 1, hi: 0, }, ), (u256::MAX, 254, u256 { lo: 0b11, hi: 0 }), (u256::MAX, 255, u256 { lo: 1, hi: 0 }), ( u256 { hi: LOHI_SPLIT, lo: 0, }, 64, u256 { lo: 0xffffffffffffffff0000000000000000, hi: 0xaaaaaaaaaaaaaaaa, }, ), ]; for (input, shift, expected) in check { let res = input >> shift; if res != expected { add_error(input, shift, expected, res); } } assert!(!has_errors); } #[test] #[should_panic] #[cfg(debug_assertions)] // FIXME(ppc): ppc64le seems to have issues with `should_panic` tests. #[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] fn shr_u256_overflow() { // Like regular shr, panic on overflow with debug assertions let _ = u256::MAX >> 256; } #[test] #[cfg(not(debug_assertions))] fn shr_u256_overflow() { // No panic without debug assertions assert_eq!(u256::MAX >> 256, u256::ZERO); assert_eq!(u256::MAX >> 257, u256::ZERO); assert_eq!(u256::MAX >> u32::MAX, u256::ZERO); } libm-0.2.15/src/math/support/big.rs000064400000000000000000000127001046102023000151770ustar 00000000000000//! Integers used for wide operations, larger than `u128`. #[cfg(test)] mod tests; use core::ops; use super::{DInt, HInt, Int, MinInt}; const U128_LO_MASK: u128 = u64::MAX as u128; /// A 256-bit unsigned integer represented as two 128-bit native-endian limbs. #[allow(non_camel_case_types)] #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] pub struct u256 { pub lo: u128, pub hi: u128, } impl u256 { #[cfg(any(test, feature = "unstable-public-internals"))] pub const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX, }; /// Reinterpret as a signed integer pub fn signed(self) -> i256 { i256 { lo: self.lo, hi: self.hi, } } } /// A 256-bit signed integer represented as two 128-bit native-endian limbs. #[allow(non_camel_case_types)] #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] pub struct i256 { pub lo: u128, pub hi: u128, } impl i256 { /// Reinterpret as an unsigned integer #[cfg(any(test, feature = "unstable-public-internals"))] pub fn unsigned(self) -> u256 { u256 { lo: self.lo, hi: self.hi, } } } impl MinInt for u256 { type OtherSign = i256; type Unsigned = u256; const SIGNED: bool = false; const BITS: u32 = 256; const ZERO: Self = Self { lo: 0, hi: 0 }; const ONE: Self = Self { lo: 1, hi: 0 }; const MIN: Self = Self { lo: 0, hi: 0 }; const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX, }; } impl MinInt for i256 { type OtherSign = u256; type Unsigned = u256; const SIGNED: bool = false; const BITS: u32 = 256; const ZERO: Self = Self { lo: 0, hi: 0 }; const ONE: Self = Self { lo: 1, hi: 0 }; const MIN: Self = Self { lo: 0, hi: 1 << 127, }; const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX << 1, }; } macro_rules! impl_common { ($ty:ty) => { impl ops::BitOr for $ty { type Output = Self; fn bitor(mut self, rhs: Self) -> Self::Output { self.lo |= rhs.lo; self.hi |= rhs.hi; self } } impl ops::Not for $ty { type Output = Self; fn not(mut self) -> Self::Output { self.lo = !self.lo; self.hi = !self.hi; self } } impl ops::Shl for $ty { type Output = Self; fn shl(self, _rhs: u32) -> Self::Output { unimplemented!("only used to meet trait bounds") } } }; } impl_common!(i256); impl_common!(u256); impl ops::Add for u256 { type Output = Self; fn add(self, rhs: Self) -> Self::Output { let (lo, carry) = self.lo.overflowing_add(rhs.lo); let hi = self.hi.wrapping_add(carry as u128).wrapping_add(rhs.hi); Self { lo, hi } } } impl ops::Shr for u256 { type Output = Self; fn shr(mut self, rhs: u32) -> Self::Output { debug_assert!(rhs < Self::BITS, "attempted to shift right with overflow"); if rhs >= Self::BITS { return Self::ZERO; } if rhs == 0 { return self; } if rhs < 128 { self.lo >>= rhs; self.lo |= self.hi << (128 - rhs); } else { self.lo = self.hi >> (rhs - 128); } if rhs < 128 { self.hi >>= rhs; } else { self.hi = 0; } self } } impl HInt for u128 { type D = u256; fn widen(self) -> Self::D { u256 { lo: self, hi: 0 } } fn zero_widen(self) -> Self::D { self.widen() } fn zero_widen_mul(self, rhs: Self) -> Self::D { let l0 = self & U128_LO_MASK; let l1 = rhs & U128_LO_MASK; let h0 = self >> 64; let h1 = rhs >> 64; let p_ll: u128 = l0.overflowing_mul(l1).0; let p_lh: u128 = l0.overflowing_mul(h1).0; let p_hl: u128 = h0.overflowing_mul(l1).0; let p_hh: u128 = h0.overflowing_mul(h1).0; let s0 = p_hl + (p_ll >> 64); let s1 = (p_ll & U128_LO_MASK) + (s0 << 64); let s2 = p_lh + (s1 >> 64); let lo = (p_ll & U128_LO_MASK) + (s2 << 64); let hi = p_hh + (s0 >> 64) + (s2 >> 64); u256 { lo, hi } } fn widen_mul(self, rhs: Self) -> Self::D { self.zero_widen_mul(rhs) } fn widen_hi(self) -> Self::D { self.widen() << ::BITS } } impl HInt for i128 { type D = i256; fn widen(self) -> Self::D { let mut ret = self.unsigned().zero_widen().signed(); if self.is_negative() { ret.hi = u128::MAX; } ret } fn zero_widen(self) -> Self::D { self.unsigned().zero_widen().signed() } fn zero_widen_mul(self, rhs: Self) -> Self::D { self.unsigned().zero_widen_mul(rhs.unsigned()).signed() } fn widen_mul(self, _rhs: Self) -> Self::D { unimplemented!("signed i128 widening multiply is not used") } fn widen_hi(self) -> Self::D { self.widen() << ::BITS } } impl DInt for u256 { type H = u128; fn lo(self) -> Self::H { self.lo } fn hi(self) -> Self::H { self.hi } } impl DInt for i256 { type H = i128; fn lo(self) -> Self::H { self.lo as i128 } fn hi(self) -> Self::H { self.hi as i128 } } libm-0.2.15/src/math/support/env.rs000064400000000000000000000111051046102023000152240ustar 00000000000000//! Support for rounding directions and status flags as specified by IEEE 754. //! //! Rust does not support the floating point environment so rounding mode is passed as an argument //! and status flags are returned as part of the result. There is currently not much support for //! this; most existing ports from musl use a form of `force_eval!` to raise exceptions, but this //! has no side effects in Rust. Further, correct behavior relies on elementary operations making //! use of the correct rounding and raising relevant exceptions, which is not the case for Rust. //! //! This module exists so no functionality is lost when porting algorithms that respect floating //! point environment, and so that some functionality may be tested (that which does not rely on //! side effects from elementary operations). Full support would require wrappers around basic //! operations, but there is no plan to add this at the current time. /// A value combined with a floating point status. pub struct FpResult { pub val: T, #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] pub status: Status, } impl FpResult { pub fn new(val: T, status: Status) -> Self { Self { val, status } } /// Return `val` with `Status::OK`. pub fn ok(val: T) -> Self { Self { val, status: Status::OK, } } } /// IEEE 754 rounding mode, excluding the optional `roundTiesToAway` version of nearest. /// /// Integer representation comes from what CORE-MATH uses for indexing. #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] #[derive(Clone, Copy, Debug, PartialEq)] pub enum Round { /// IEEE 754 nearest, `roundTiesToEven`. Nearest = 0, /// IEEE 754 `roundTowardNegative`. Negative = 1, /// IEEE 754 `roundTowardPositive`. Positive = 2, /// IEEE 754 `roundTowardZero`. Zero = 3, } /// IEEE 754 exception status flags. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Status(u8); impl Status { /// Default status indicating no errors. pub const OK: Self = Self(0); /// No definable result. /// /// Includes: /// - Any ops on sNaN, with a few exceptions. /// - `0 * inf`, `inf * 0`. /// - `fma(0, inf, c)` or `fma(inf, 0, c)`, possibly excluding `c = qNaN`. /// - `+inf + -inf` and similar (includes subtraction and fma). /// - `0.0 / 0.0`, `inf / inf` /// - `remainder(x, y)` if `y == 0.0` or `x == inf`, and neither is NaN. /// - `sqrt(x)` with `x < 0.0`. pub const INVALID: Self = Self(1); /// Division by zero. /// /// The default result for division is +/-inf based on operand sign. For `logB`, the default /// result is -inf. /// `x / y` when `x != 0.0` and `y == 0.0`, #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] pub const DIVIDE_BY_ZERO: Self = Self(1 << 2); /// The result exceeds the maximum finite value. /// /// The default result depends on rounding mode. `Nearest*` rounds to +/- infinity, sign based /// on the intermediate result. `Zero` rounds to the signed maximum finite. `Positive` and /// `Negative` round to signed maximum finite in one direction, signed infinity in the other. #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] pub const OVERFLOW: Self = Self(1 << 3); /// The result is subnormal and lost precision. pub const UNDERFLOW: Self = Self(1 << 4); /// The finite-precision result does not match that of infinite precision, and the reason /// is not represented by one of the other flags. pub const INEXACT: Self = Self(1 << 5); /// True if `UNDERFLOW` is set. #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] pub const fn underflow(self) -> bool { self.0 & Self::UNDERFLOW.0 != 0 } /// True if `OVERFLOW` is set. #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] pub const fn overflow(self) -> bool { self.0 & Self::OVERFLOW.0 != 0 } pub fn set_underflow(&mut self, val: bool) { self.set_flag(val, Self::UNDERFLOW); } /// True if `INEXACT` is set. pub const fn inexact(self) -> bool { self.0 & Self::INEXACT.0 != 0 } pub fn set_inexact(&mut self, val: bool) { self.set_flag(val, Self::INEXACT); } fn set_flag(&mut self, val: bool, mask: Self) { if val { self.0 |= mask.0; } else { self.0 &= !mask.0; } } pub(crate) const fn with(self, rhs: Self) -> Self { Self(self.0 | rhs.0) } } libm-0.2.15/src/math/support/feature_detect.rs000064400000000000000000000147161046102023000174320ustar 00000000000000//! Helpers for runtime target feature detection that are shared across architectures. // `AtomicU32` is preferred for a consistent size across targets. #[cfg(all(target_has_atomic = "ptr", not(target_has_atomic = "32")))] compile_error!("currently all targets that support `AtomicPtr` also support `AtomicU32`"); use core::sync::atomic::{AtomicU32, Ordering}; /// Given a list of identifiers, assign each one a unique sequential single-bit mask. #[allow(unused_macros)] macro_rules! unique_masks { ($ty:ty, $($name:ident,)+) => { #[cfg(test)] pub const ALL: &[$ty] = &[$($name),+]; #[cfg(test)] pub const NAMES: &[&str] = &[$(stringify!($name)),+]; unique_masks!(@one; $ty; 0; $($name,)+); }; // Matcher for a single value (@one; $_ty:ty; $_idx:expr;) => {}; (@one; $ty:ty; $shift:expr; $name:ident, $($tail:tt)*) => { pub const $name: $ty = 1 << $shift; // Ensure the top bit is not used since it stores initialized state. const _: () = assert!($name != (1 << (<$ty>::BITS - 1))); // Increment the shift and invoke the next unique_masks!(@one; $ty; $shift + 1; $($tail)*); }; } /// Call `init` once to choose an implementation, then use it for the rest of the program. /// /// - `sig` is the function type. /// - `init` is an expression called at startup that chooses an implementation and returns a /// function pointer. /// - `call` is an expression to call a function returned by `init`, encapsulating any safety /// preconditions. /// /// The type `Func` is available in `init` and `call`. /// /// This is effectively our version of an ifunc without linker support. Note that `init` may be /// called more than once until one completes. #[allow(unused_macros)] // only used on some architectures macro_rules! select_once { ( sig: fn($($arg:ident: $ArgTy:ty),*) -> $RetTy:ty, init: $init:expr, call: $call:expr, ) => {{ use core::mem; use core::sync::atomic::{AtomicPtr, Ordering}; type Func = unsafe fn($($arg: $ArgTy),*) -> $RetTy; /// Stores a pointer that is immediately jumped to. By default it is an init function /// that sets FUNC to something else. static FUNC: AtomicPtr<()> = AtomicPtr::new((initializer as Func) as *mut ()); /// Run once to set the function that will be used for all subsequent calls. fn initializer($($arg: $ArgTy),*) -> $RetTy { // Select an implementation, ensuring a 'static lifetime. let fn_ptr: Func = $init(); FUNC.store(fn_ptr as *mut (), Ordering::Relaxed); // Forward the call to the selected function. $call(fn_ptr) } let raw: *mut () = FUNC.load(Ordering::Relaxed); // SAFETY: will only ever be `initializer` or another function pointer that has the // 'static lifetime. let fn_ptr: Func = unsafe { mem::transmute::<*mut (), Func>(raw) }; $call(fn_ptr) }} } #[allow(unused_imports)] pub(crate) use {select_once, unique_masks}; use crate::support::cold_path; /// Helper for working with bit flags, based on `bitflags`. #[derive(Clone, Copy, Debug, PartialEq)] pub struct Flags(u32); #[allow(dead_code)] // only used on some architectures impl Flags { /// No bits set. pub const fn empty() -> Self { Self(0) } /// Create with bits already set. pub const fn from_bits(val: u32) -> Self { Self(val) } /// Get the integer representation. pub fn bits(&self) -> u32 { self.0 } /// Set any bits in `mask`. pub fn insert(&mut self, mask: u32) { self.0 |= mask; } /// Check whether the mask is set. pub fn contains(&self, mask: u32) -> bool { self.0 & mask == mask } /// Check whether the nth bit is set. pub fn test_nth(&self, bit: u32) -> bool { debug_assert!(bit < u32::BITS, "bit index out-of-bounds"); self.0 & (1 << bit) != 0 } } /// Load flags from an atomic value. If the flags have not yet been initialized, call `init` /// to do so. /// /// Note that `init` may run more than once. #[allow(dead_code)] // only used on some architectures pub fn get_or_init_flags_cache(cache: &AtomicU32, init: impl FnOnce() -> Flags) -> Flags { // The top bit is used to indicate that the values have already been set once. const INITIALIZED: u32 = 1 << 31; // Relaxed ops are sufficient since the result should always be the same. let mut flags = Flags::from_bits(cache.load(Ordering::Relaxed)); if !flags.contains(INITIALIZED) { // Without this, `init` is inlined and the bit check gets wrapped in `init`'s lengthy // prologue/epilogue. Cold pathing gives a preferable load->test->?jmp->ret. cold_path(); flags = init(); debug_assert!( !flags.contains(INITIALIZED), "initialized bit shouldn't be set" ); flags.insert(INITIALIZED); cache.store(flags.bits(), Ordering::Relaxed); } flags } #[cfg(test)] mod tests { use super::*; #[test] fn unique_masks() { unique_masks! { u32, V0, V1, V2, } assert_eq!(V0, 1u32 << 0); assert_eq!(V1, 1u32 << 1); assert_eq!(V2, 1u32 << 2); assert_eq!(ALL, [V0, V1, V2]); assert_eq!(NAMES, ["V0", "V1", "V2"]); } #[test] fn flag_cache_is_used() { // Sanity check that flags are only ever set once static CACHE: AtomicU32 = AtomicU32::new(0); let mut f1 = Flags::from_bits(0x1); let f2 = Flags::from_bits(0x2); let r1 = get_or_init_flags_cache(&CACHE, || f1); let r2 = get_or_init_flags_cache(&CACHE, || f2); f1.insert(1 << 31); // init bit assert_eq!(r1, f1); assert_eq!(r2, f1); } #[test] fn select_cache_is_used() { // Sanity check that cache is used static CALLED: AtomicU32 = AtomicU32::new(0); fn inner() { fn nop() {} select_once! { sig: fn() -> (), init: || { CALLED.fetch_add(1, Ordering::Relaxed); nop }, call: |fn_ptr: Func| unsafe { fn_ptr() }, } } // `init` should only have been called once. inner(); assert_eq!(CALLED.load(Ordering::Relaxed), 1); inner(); assert_eq!(CALLED.load(Ordering::Relaxed), 1); } } libm-0.2.15/src/math/support/float_traits.rs000064400000000000000000000411541046102023000171360ustar 00000000000000#![allow(unknown_lints)] // FIXME(msrv) we shouldn't need this use core::{fmt, mem, ops}; use super::int_traits::{CastFrom, Int, MinInt}; /// Trait for some basic operations on floats // #[allow(dead_code)] pub trait Float: Copy + fmt::Debug + PartialEq + PartialOrd + ops::AddAssign + ops::MulAssign + ops::Add + ops::Sub + ops::Mul + ops::Div + ops::Rem + ops::Neg + 'static { /// A uint of the same width as the float type Int: Int; /// A int of the same width as the float type SignedInt: Int + MinInt + ops::Neg; const ZERO: Self; const NEG_ZERO: Self; const ONE: Self; const NEG_ONE: Self; const INFINITY: Self; const NEG_INFINITY: Self; const NAN: Self; const NEG_NAN: Self; const MAX: Self; const MIN: Self; const EPSILON: Self; const PI: Self; const NEG_PI: Self; const FRAC_PI_2: Self; const MIN_POSITIVE_NORMAL: Self; /// The bitwidth of the float type const BITS: u32; /// The bitwidth of the significand const SIG_BITS: u32; /// The bitwidth of the exponent const EXP_BITS: u32 = Self::BITS - Self::SIG_BITS - 1; /// The saturated (maximum bitpattern) value of the exponent, i.e. the infinite /// representation. /// /// This shifted fully right, use `EXP_MASK` for the shifted value. const EXP_SAT: u32 = (1 << Self::EXP_BITS) - 1; /// The exponent bias value const EXP_BIAS: u32 = Self::EXP_SAT >> 1; /// Maximum unbiased exponent value. const EXP_MAX: i32 = Self::EXP_BIAS as i32; /// Minimum *NORMAL* unbiased exponent value. const EXP_MIN: i32 = -(Self::EXP_MAX - 1); /// Minimum subnormal exponent value. const EXP_MIN_SUBNORM: i32 = Self::EXP_MIN - Self::SIG_BITS as i32; /// A mask for the sign bit const SIGN_MASK: Self::Int; /// A mask for the significand const SIG_MASK: Self::Int; /// A mask for the exponent const EXP_MASK: Self::Int; /// The implicit bit of the float format const IMPLICIT_BIT: Self::Int; /// Returns `self` transmuted to `Self::Int` fn to_bits(self) -> Self::Int; /// Returns `self` transmuted to `Self::SignedInt` #[allow(dead_code)] fn to_bits_signed(self) -> Self::SignedInt { self.to_bits().signed() } /// Check bitwise equality. #[allow(dead_code)] fn biteq(self, rhs: Self) -> bool { self.to_bits() == rhs.to_bits() } /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be /// represented in multiple different ways. /// /// This method returns `true` if two NaNs are compared. Use [`biteq`](Self::biteq) instead /// if `NaN` should not be treated separately. #[allow(dead_code)] fn eq_repr(self, rhs: Self) -> bool { if self.is_nan() && rhs.is_nan() { true } else { self.biteq(rhs) } } /// Returns true if the value is NaN. fn is_nan(self) -> bool; /// Returns true if the value is +inf or -inf. fn is_infinite(self) -> bool; /// Returns true if the sign is negative. Extracts the sign bit regardless of zero or NaN. fn is_sign_negative(self) -> bool; /// Returns true if the sign is positive. Extracts the sign bit regardless of zero or NaN. fn is_sign_positive(self) -> bool { !self.is_sign_negative() } /// Returns if `self` is subnormal. #[allow(dead_code)] fn is_subnormal(self) -> bool { (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO } /// Returns the exponent, not adjusting for bias, not accounting for subnormals or zero. fn ex(self) -> u32 { u32::cast_from(self.to_bits() >> Self::SIG_BITS) & Self::EXP_SAT } /// Extract the exponent and adjust it for bias, not accounting for subnormals or zero. fn exp_unbiased(self) -> i32 { self.ex().signed() - (Self::EXP_BIAS as i32) } /// Returns the significand with no implicit bit (or the "fractional" part) #[allow(dead_code)] fn frac(self) -> Self::Int { self.to_bits() & Self::SIG_MASK } /// Returns a `Self::Int` transmuted back to `Self` fn from_bits(a: Self::Int) -> Self; /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. fn from_parts(negative: bool, exponent: u32, significand: Self::Int) -> Self { let sign = if negative { Self::Int::ONE } else { Self::Int::ZERO }; Self::from_bits( (sign << (Self::BITS - 1)) | (Self::Int::cast_from(exponent & Self::EXP_SAT) << Self::SIG_BITS) | (significand & Self::SIG_MASK), ) } #[allow(dead_code)] fn abs(self) -> Self; /// Returns a number composed of the magnitude of self and the sign of sign. fn copysign(self, other: Self) -> Self; /// Fused multiply add, rounding once. fn fma(self, y: Self, z: Self) -> Self; /// Returns (normalized exponent, normalized significand) #[allow(dead_code)] fn normalize(significand: Self::Int) -> (i32, Self::Int); /// Returns a number that represents the sign of self. #[allow(dead_code)] fn signum(self) -> Self { if self.is_nan() { self } else { Self::ONE.copysign(self) } } } /// Access the associated `Int` type from a float (helper to avoid ambiguous associated types). pub type IntTy = ::Int; macro_rules! float_impl { ( $ty:ident, $ity:ident, $sity:ident, $bits:expr, $significand_bits:expr, $from_bits:path, $to_bits:path, $fma_fn:ident, $fma_intrinsic:ident ) => { impl Float for $ty { type Int = $ity; type SignedInt = $sity; const ZERO: Self = 0.0; const NEG_ZERO: Self = -0.0; const ONE: Self = 1.0; const NEG_ONE: Self = -1.0; const INFINITY: Self = Self::INFINITY; const NEG_INFINITY: Self = Self::NEG_INFINITY; const NAN: Self = Self::NAN; // NAN isn't guaranteed to be positive but it usually is. We only use this for // tests. const NEG_NAN: Self = $from_bits($to_bits(Self::NAN) | Self::SIGN_MASK); const MAX: Self = -Self::MIN; // Sign bit set, saturated mantissa, saturated exponent with last bit zeroed const MIN: Self = $from_bits(Self::Int::MAX & !(1 << Self::SIG_BITS)); const EPSILON: Self = <$ty>::EPSILON; // Exponent is a 1 in the LSB const MIN_POSITIVE_NORMAL: Self = $from_bits(1 << Self::SIG_BITS); const PI: Self = core::$ty::consts::PI; const NEG_PI: Self = -Self::PI; const FRAC_PI_2: Self = core::$ty::consts::FRAC_PI_2; const BITS: u32 = $bits; const SIG_BITS: u32 = $significand_bits; const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); const SIG_MASK: Self::Int = (1 << Self::SIG_BITS) - 1; const EXP_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIG_MASK); const IMPLICIT_BIT: Self::Int = 1 << Self::SIG_BITS; fn to_bits(self) -> Self::Int { self.to_bits() } fn is_nan(self) -> bool { self.is_nan() } fn is_infinite(self) -> bool { self.is_infinite() } fn is_sign_negative(self) -> bool { self.is_sign_negative() } fn from_bits(a: Self::Int) -> Self { Self::from_bits(a) } fn abs(self) -> Self { cfg_if! { // FIXME(msrv): `abs` is available in `core` starting with 1.85. if #[cfg(intrinsics_enabled)] { self.abs() } else { super::super::generic::fabs(self) } } } fn copysign(self, other: Self) -> Self { cfg_if! { // FIXME(msrv): `copysign` is available in `core` starting with 1.85. if #[cfg(intrinsics_enabled)] { self.copysign(other) } else { super::super::generic::copysign(self, other) } } } fn fma(self, y: Self, z: Self) -> Self { cfg_if! { // fma is not yet available in `core` if #[cfg(intrinsics_enabled)] { unsafe{ core::intrinsics::$fma_intrinsic(self, y, z) } } else { super::super::$fma_fn(self, y, z) } } } fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS); ( 1i32.wrapping_sub(shift as i32), significand << shift as Self::Int, ) } } }; } #[cfg(f16_enabled)] float_impl!( f16, u16, i16, 16, 10, f16::from_bits, f16::to_bits, fmaf16, fmaf16 ); float_impl!( f32, u32, i32, 32, 23, f32_from_bits, f32_to_bits, fmaf, fmaf32 ); float_impl!( f64, u64, i64, 64, 52, f64_from_bits, f64_to_bits, fma, fmaf64 ); #[cfg(f128_enabled)] float_impl!( f128, u128, i128, 128, 112, f128::from_bits, f128::to_bits, fmaf128, fmaf128 ); /* FIXME(msrv): vendor some things that are not const stable at our MSRV */ /// `f32::from_bits` #[allow(unnecessary_transmutes)] // lint appears in newer versions of Rust pub const fn f32_from_bits(bits: u32) -> f32 { // SAFETY: POD cast with no preconditions unsafe { mem::transmute::(bits) } } /// `f32::to_bits` #[allow(unnecessary_transmutes)] // lint appears in newer versions of Rust pub const fn f32_to_bits(x: f32) -> u32 { // SAFETY: POD cast with no preconditions unsafe { mem::transmute::(x) } } /// `f64::from_bits` #[allow(unnecessary_transmutes)] // lint appears in newer versions of Rust pub const fn f64_from_bits(bits: u64) -> f64 { // SAFETY: POD cast with no preconditions unsafe { mem::transmute::(bits) } } /// `f64::to_bits` #[allow(unnecessary_transmutes)] // lint appears in newer versions of Rust pub const fn f64_to_bits(x: f64) -> u64 { // SAFETY: POD cast with no preconditions unsafe { mem::transmute::(x) } } /// Trait for floats twice the bit width of another integer. pub trait DFloat: Float { /// Float that is half the bit width of the floatthis trait is implemented for. type H: HFloat; /// Narrow the float type. fn narrow(self) -> Self::H; } /// Trait for floats half the bit width of another float. pub trait HFloat: Float { /// Float that is double the bit width of the float this trait is implemented for. type D: DFloat; /// Widen the float type. fn widen(self) -> Self::D; } macro_rules! impl_d_float { ($($X:ident $D:ident),*) => { $( impl DFloat for $D { type H = $X; fn narrow(self) -> Self::H { self as $X } } )* }; } macro_rules! impl_h_float { ($($H:ident $X:ident),*) => { $( impl HFloat for $H { type D = $X; fn widen(self) -> Self::D { self as $X } } )* }; } impl_d_float!(f32 f64); #[cfg(f16_enabled)] impl_d_float!(f16 f32); #[cfg(f128_enabled)] impl_d_float!(f64 f128); impl_h_float!(f32 f64); #[cfg(f16_enabled)] impl_h_float!(f16 f32); #[cfg(f128_enabled)] impl_h_float!(f64 f128); #[cfg(test)] mod tests { use super::*; #[test] #[cfg(f16_enabled)] fn check_f16() { // Constants assert_eq!(f16::EXP_SAT, 0b11111); assert_eq!(f16::EXP_BIAS, 15); assert_eq!(f16::EXP_MAX, 15); assert_eq!(f16::EXP_MIN, -14); assert_eq!(f16::EXP_MIN_SUBNORM, -24); // `exp_unbiased` assert_eq!(f16::FRAC_PI_2.exp_unbiased(), 0); assert_eq!((1.0f16 / 2.0).exp_unbiased(), -1); assert_eq!(f16::MAX.exp_unbiased(), 15); assert_eq!(f16::MIN.exp_unbiased(), 15); assert_eq!(f16::MIN_POSITIVE.exp_unbiased(), -14); // This is a convenience method and not ldexp, `exp_unbiased` does not return correct // results for zero and subnormals. assert_eq!(f16::ZERO.exp_unbiased(), -15); assert_eq!(f16::from_bits(0x1).exp_unbiased(), -15); assert_eq!(f16::MIN_POSITIVE, f16::MIN_POSITIVE_NORMAL); // `from_parts` assert_biteq!(f16::from_parts(true, f16::EXP_BIAS, 0), -1.0f16); assert_biteq!(f16::from_parts(false, 0, 1), f16::from_bits(0x1)); } #[test] fn check_f32() { // Constants assert_eq!(f32::EXP_SAT, 0b11111111); assert_eq!(f32::EXP_BIAS, 127); assert_eq!(f32::EXP_MAX, 127); assert_eq!(f32::EXP_MIN, -126); assert_eq!(f32::EXP_MIN_SUBNORM, -149); // `exp_unbiased` assert_eq!(f32::FRAC_PI_2.exp_unbiased(), 0); assert_eq!((1.0f32 / 2.0).exp_unbiased(), -1); assert_eq!(f32::MAX.exp_unbiased(), 127); assert_eq!(f32::MIN.exp_unbiased(), 127); assert_eq!(f32::MIN_POSITIVE.exp_unbiased(), -126); // This is a convenience method and not ldexp, `exp_unbiased` does not return correct // results for zero and subnormals. assert_eq!(f32::ZERO.exp_unbiased(), -127); assert_eq!(f32::from_bits(0x1).exp_unbiased(), -127); assert_eq!(f32::MIN_POSITIVE, f32::MIN_POSITIVE_NORMAL); // `from_parts` assert_biteq!(f32::from_parts(true, f32::EXP_BIAS, 0), -1.0f32); assert_biteq!( f32::from_parts(false, 10 + f32::EXP_BIAS, 0), hf32!("0x1p10") ); assert_biteq!(f32::from_parts(false, 0, 1), f32::from_bits(0x1)); } #[test] fn check_f64() { // Constants assert_eq!(f64::EXP_SAT, 0b11111111111); assert_eq!(f64::EXP_BIAS, 1023); assert_eq!(f64::EXP_MAX, 1023); assert_eq!(f64::EXP_MIN, -1022); assert_eq!(f64::EXP_MIN_SUBNORM, -1074); // `exp_unbiased` assert_eq!(f64::FRAC_PI_2.exp_unbiased(), 0); assert_eq!((1.0f64 / 2.0).exp_unbiased(), -1); assert_eq!(f64::MAX.exp_unbiased(), 1023); assert_eq!(f64::MIN.exp_unbiased(), 1023); assert_eq!(f64::MIN_POSITIVE.exp_unbiased(), -1022); // This is a convenience method and not ldexp, `exp_unbiased` does not return correct // results for zero and subnormals. assert_eq!(f64::ZERO.exp_unbiased(), -1023); assert_eq!(f64::from_bits(0x1).exp_unbiased(), -1023); assert_eq!(f64::MIN_POSITIVE, f64::MIN_POSITIVE_NORMAL); // `from_parts` assert_biteq!(f64::from_parts(true, f64::EXP_BIAS, 0), -1.0f64); assert_biteq!( f64::from_parts(false, 10 + f64::EXP_BIAS, 0), hf64!("0x1p10") ); assert_biteq!(f64::from_parts(false, 0, 1), f64::from_bits(0x1)); } #[test] #[cfg(f128_enabled)] fn check_f128() { // Constants assert_eq!(f128::EXP_SAT, 0b111111111111111); assert_eq!(f128::EXP_BIAS, 16383); assert_eq!(f128::EXP_MAX, 16383); assert_eq!(f128::EXP_MIN, -16382); assert_eq!(f128::EXP_MIN_SUBNORM, -16494); // `exp_unbiased` assert_eq!(f128::FRAC_PI_2.exp_unbiased(), 0); assert_eq!((1.0f128 / 2.0).exp_unbiased(), -1); assert_eq!(f128::MAX.exp_unbiased(), 16383); assert_eq!(f128::MIN.exp_unbiased(), 16383); assert_eq!(f128::MIN_POSITIVE.exp_unbiased(), -16382); // This is a convenience method and not ldexp, `exp_unbiased` does not return correct // results for zero and subnormals. assert_eq!(f128::ZERO.exp_unbiased(), -16383); assert_eq!(f128::from_bits(0x1).exp_unbiased(), -16383); assert_eq!(f128::MIN_POSITIVE, f128::MIN_POSITIVE_NORMAL); // `from_parts` assert_biteq!(f128::from_parts(true, f128::EXP_BIAS, 0), -1.0f128); assert_biteq!(f128::from_parts(false, 0, 1), f128::from_bits(0x1)); } } libm-0.2.15/src/math/support/hex_float.rs000064400000000000000000001127601046102023000164160ustar 00000000000000//! Utilities for working with hex float formats. use core::fmt; use super::{Float, Round, Status, f32_from_bits, f64_from_bits}; /// Construct a 16-bit float from hex float representation (C-style) #[cfg(f16_enabled)] pub const fn hf16(s: &str) -> f16 { match parse_hex_exact(s, 16, 10) { Ok(bits) => f16::from_bits(bits as u16), Err(HexFloatParseError(s)) => panic!("{}", s), } } /// Construct a 32-bit float from hex float representation (C-style) #[allow(unused)] pub const fn hf32(s: &str) -> f32 { match parse_hex_exact(s, 32, 23) { Ok(bits) => f32_from_bits(bits as u32), Err(HexFloatParseError(s)) => panic!("{}", s), } } /// Construct a 64-bit float from hex float representation (C-style) pub const fn hf64(s: &str) -> f64 { match parse_hex_exact(s, 64, 52) { Ok(bits) => f64_from_bits(bits as u64), Err(HexFloatParseError(s)) => panic!("{}", s), } } /// Construct a 128-bit float from hex float representation (C-style) #[cfg(f128_enabled)] pub const fn hf128(s: &str) -> f128 { match parse_hex_exact(s, 128, 112) { Ok(bits) => f128::from_bits(bits), Err(HexFloatParseError(s)) => panic!("{}", s), } } #[derive(Copy, Clone, Debug)] pub struct HexFloatParseError(&'static str); /// Parses any float to its bitwise representation, returning an error if it cannot be represented exactly pub const fn parse_hex_exact( s: &str, bits: u32, sig_bits: u32, ) -> Result { match parse_any(s, bits, sig_bits, Round::Nearest) { Err(e) => Err(e), Ok((bits, Status::OK)) => Ok(bits), Ok((_, status)) if status.overflow() => Err(HexFloatParseError("the value is too huge")), Ok((_, status)) if status.underflow() => Err(HexFloatParseError("the value is too tiny")), Ok((_, status)) if status.inexact() => Err(HexFloatParseError("the value is too precise")), Ok(_) => unreachable!(), } } /// Parse any float from hex to its bitwise representation. pub const fn parse_any( s: &str, bits: u32, sig_bits: u32, round: Round, ) -> Result<(u128, Status), HexFloatParseError> { let mut b = s.as_bytes(); if sig_bits > 119 || bits > 128 || bits < sig_bits + 3 || bits > sig_bits + 30 { return Err(HexFloatParseError("unsupported target float configuration")); } let neg = matches!(b, [b'-', ..]); if let &[b'-' | b'+', ref rest @ ..] = b { b = rest; } let sign_bit = 1 << (bits - 1); let quiet_bit = 1 << (sig_bits - 1); let nan = sign_bit - quiet_bit; let inf = nan - quiet_bit; let (mut x, status) = match *b { [b'i' | b'I', b'n' | b'N', b'f' | b'F'] => (inf, Status::OK), [b'n' | b'N', b'a' | b'A', b'n' | b'N'] => (nan, Status::OK), [b'0', b'x' | b'X', ref rest @ ..] => { let round = match (neg, round) { // parse("-x", Round::Positive) == -parse("x", Round::Negative) (true, Round::Positive) => Round::Negative, (true, Round::Negative) => Round::Positive, // rounding toward nearest or zero are symmetric (true, Round::Nearest | Round::Zero) | (false, _) => round, }; match parse_finite(rest, bits, sig_bits, round) { Err(e) => return Err(e), Ok(res) => res, } } _ => return Err(HexFloatParseError("no hex indicator")), }; if neg { x ^= sign_bit; } Ok((x, status)) } const fn parse_finite( b: &[u8], bits: u32, sig_bits: u32, rounding_mode: Round, ) -> Result<(u128, Status), HexFloatParseError> { let exp_bits: u32 = bits - sig_bits - 1; let max_msb: i32 = (1 << (exp_bits - 1)) - 1; // The exponent of one ULP in the subnormals let min_lsb: i32 = 1 - max_msb - sig_bits as i32; let (mut sig, mut exp) = match parse_hex(b) { Err(e) => return Err(e), Ok(Parsed { sig: 0, .. }) => return Ok((0, Status::OK)), Ok(Parsed { sig, exp }) => (sig, exp), }; let mut round_bits = u128_ilog2(sig) as i32 - sig_bits as i32; // Round at least up to min_lsb if exp < min_lsb - round_bits { round_bits = min_lsb - exp; } let mut status = Status::OK; exp += round_bits; if round_bits > 0 { // first, prepare for rounding exactly two bits if round_bits == 1 { sig <<= 1; } else if round_bits > 2 { sig = shr_odd_rounding(sig, (round_bits - 2) as u32); } if sig & 0b11 != 0 { status = Status::INEXACT; } sig = shr2_round(sig, rounding_mode); } else if round_bits < 0 { sig <<= -round_bits; } // The parsed value is X = sig * 2^exp // Expressed as a multiple U of the smallest subnormal value: // X = U * 2^min_lsb, so U = sig * 2^(exp-min_lsb) let uexp = (exp - min_lsb) as u128; let uexp = uexp << sig_bits; // Note that it is possible for the exponent bits to equal 2 here // if the value rounded up, but that means the mantissa is all zeroes // so the value is still correct debug_assert!(sig <= 2 << sig_bits); let inf = ((1 << exp_bits) - 1) << sig_bits; let bits = match sig.checked_add(uexp) { Some(bits) if bits < inf => { // inexact subnormal or zero? if status.inexact() && bits < (1 << sig_bits) { status = status.with(Status::UNDERFLOW); } bits } _ => { // overflow to infinity status = status.with(Status::OVERFLOW).with(Status::INEXACT); match rounding_mode { Round::Positive | Round::Nearest => inf, Round::Negative | Round::Zero => inf - 1, } } }; Ok((bits, status)) } /// Shift right, rounding all inexact divisions to the nearest odd number /// E.g. (0 >> 4) -> 0, (1..=31 >> 4) -> 1, (32 >> 4) -> 2, ... /// /// Useful for reducing a number before rounding the last two bits, since /// the result of the final rounding is preserved for all rounding modes. const fn shr_odd_rounding(x: u128, k: u32) -> u128 { if k < 128 { let inexact = x.trailing_zeros() < k; (x >> k) | (inexact as u128) } else { (x != 0) as u128 } } /// Divide by 4, rounding with the given mode const fn shr2_round(mut x: u128, round: Round) -> u128 { let t = (x as u32) & 0b111; x >>= 2; match round { // Look-up-table on the last three bits for when to round up Round::Nearest => x + ((0b11001000_u8 >> t) & 1) as u128, Round::Negative => x, Round::Zero => x, Round::Positive => x + (t & 0b11 != 0) as u128, } } /// A parsed finite and unsigned floating point number. struct Parsed { /// Absolute value sig * 2^exp sig: u128, exp: i32, } /// Parse a hexadecimal float x const fn parse_hex(mut b: &[u8]) -> Result { let mut sig: u128 = 0; let mut exp: i32 = 0; let mut seen_point = false; let mut some_digits = false; let mut inexact = false; while let &[c, ref rest @ ..] = b { b = rest; match c { b'.' => { if seen_point { return Err(HexFloatParseError( "unexpected '.' parsing fractional digits", )); } seen_point = true; continue; } b'p' | b'P' => break, c => { let digit = match hex_digit(c) { Some(d) => d, None => return Err(HexFloatParseError("expected hexadecimal digit")), }; some_digits = true; if (sig >> 124) == 0 { sig <<= 4; sig |= digit as u128; } else { // FIXME: it is technically possible for exp to overflow if parsing a string with >500M digits exp += 4; inexact |= digit != 0; } // Up until the fractional point, the value grows // with more digits, but after it the exponent is // compensated to match. if seen_point { exp -= 4; } } } } // If we've set inexact, the exact value has more than 125 // significant bits, and lies somewhere between sig and sig + 1. // Because we'll round off at least two of the trailing bits, // setting the last bit gives correct rounding for inexact values. sig |= inexact as u128; if !some_digits { return Err(HexFloatParseError("at least one digit is required")); }; some_digits = false; let negate_exp = matches!(b, [b'-', ..]); if let &[b'-' | b'+', ref rest @ ..] = b { b = rest; } let mut pexp: u32 = 0; while let &[c, ref rest @ ..] = b { b = rest; let digit = match dec_digit(c) { Some(d) => d, None => return Err(HexFloatParseError("expected decimal digit")), }; some_digits = true; pexp = pexp.saturating_mul(10); pexp += digit as u32; } if !some_digits { return Err(HexFloatParseError( "at least one exponent digit is required", )); }; { let e; if negate_exp { e = (exp as i64) - (pexp as i64); } else { e = (exp as i64) + (pexp as i64); }; exp = if e < i32::MIN as i64 { i32::MIN } else if e > i32::MAX as i64 { i32::MAX } else { e as i32 }; } /* FIXME(msrv): once MSRV >= 1.66, replace the above workaround block with: if negate_exp { exp = exp.saturating_sub_unsigned(pexp); } else { exp = exp.saturating_add_unsigned(pexp); }; */ Ok(Parsed { sig, exp }) } const fn dec_digit(c: u8) -> Option { match c { b'0'..=b'9' => Some(c - b'0'), _ => None, } } const fn hex_digit(c: u8) -> Option { match c { b'0'..=b'9' => Some(c - b'0'), b'a'..=b'f' => Some(c - b'a' + 10), b'A'..=b'F' => Some(c - b'A' + 10), _ => None, } } /* FIXME(msrv): vendor some things that are not const stable at our MSRV */ /// `u128::ilog2` const fn u128_ilog2(v: u128) -> u32 { assert!(v != 0); u128::BITS - 1 - v.leading_zeros() } /// Format a floating point number as its IEEE hex (`%a`) representation. pub struct Hexf(pub F); // Adapted from https://github.com/ericseppanen/hexfloat2/blob/a5c27932f0ff/src/format.rs #[cfg(not(feature = "compiler-builtins"))] fn fmt_any_hex(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::Result { if x.is_sign_negative() { write!(f, "-")?; } if x.is_nan() { return write!(f, "NaN"); } else if x.is_infinite() { return write!(f, "inf"); } else if *x == F::ZERO { return write!(f, "0x0p+0"); } let mut exponent = x.exp_unbiased(); let sig = x.to_bits() & F::SIG_MASK; let bias = F::EXP_BIAS as i32; // The mantissa MSB needs to be shifted up to the nearest nibble. let mshift = (4 - (F::SIG_BITS % 4)) % 4; let sig = sig << mshift; // The width is rounded up to the nearest char (4 bits) let mwidth = (F::SIG_BITS as usize + 3) / 4; let leading = if exponent == -bias { // subnormal number means we shift our output by 1 bit. exponent += 1; "0." } else { "1." }; write!(f, "0x{leading}{sig:0mwidth$x}p{exponent:+}") } #[cfg(feature = "compiler-builtins")] fn fmt_any_hex(_x: &F, _f: &mut fmt::Formatter<'_>) -> fmt::Result { unimplemented!() } impl fmt::LowerHex for Hexf { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { cfg_if! { if #[cfg(feature = "compiler-builtins")] { let _ = f; unimplemented!() } else { fmt_any_hex(&self.0, f) } } } } impl fmt::LowerHex for Hexf<(F, F)> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { cfg_if! { if #[cfg(feature = "compiler-builtins")] { let _ = f; unimplemented!() } else { write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) } } } } impl fmt::LowerHex for Hexf<(F, i32)> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { cfg_if! { if #[cfg(feature = "compiler-builtins")] { let _ = f; unimplemented!() } else { write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) } } } } impl fmt::LowerHex for Hexf { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { cfg_if! { if #[cfg(feature = "compiler-builtins")] { let _ = f; unimplemented!() } else { fmt::LowerHex::fmt(&self.0, f) } } } } impl fmt::Debug for Hexf where Hexf: fmt::LowerHex, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { cfg_if! { if #[cfg(feature = "compiler-builtins")] { let _ = f; unimplemented!() } else { fmt::LowerHex::fmt(self, f) } } } } impl fmt::Display for Hexf where Hexf: fmt::LowerHex, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { cfg_if! { if #[cfg(feature = "compiler-builtins")] { let _ = f; unimplemented!() } else { fmt::LowerHex::fmt(self, f) } } } } #[cfg(test)] mod parse_tests { extern crate std; use std::{format, println}; use super::*; #[cfg(f16_enabled)] fn rounding_properties(s: &str) -> Result<(), HexFloatParseError> { let (xd, s0) = parse_any(s, 16, 10, Round::Negative)?; let (xu, s1) = parse_any(s, 16, 10, Round::Positive)?; let (xz, s2) = parse_any(s, 16, 10, Round::Zero)?; let (xn, s3) = parse_any(s, 16, 10, Round::Nearest)?; // FIXME: A value between the least normal and largest subnormal // could have underflow status depend on rounding mode. if let Status::OK = s0 { // an exact result is the same for all rounding modes assert_eq!(s0, s1); assert_eq!(s0, s2); assert_eq!(s0, s3); assert_eq!(xd, xu); assert_eq!(xd, xz); assert_eq!(xd, xn); } else { assert!([s0, s1, s2, s3].into_iter().all(Status::inexact)); let xd = f16::from_bits(xd as u16); let xu = f16::from_bits(xu as u16); let xz = f16::from_bits(xz as u16); let xn = f16::from_bits(xn as u16); assert_biteq!(xd.next_up(), xu, "s={s}, xd={xd:?}, xu={xu:?}"); let signs = [xd, xu, xz, xn].map(f16::is_sign_negative); if signs == [true; 4] { assert_biteq!(xz, xu); } else { assert_eq!(signs, [false; 4]); assert_biteq!(xz, xd); } if xn.to_bits() != xd.to_bits() { assert_biteq!(xn, xu); } } Ok(()) } #[test] #[cfg(f16_enabled)] fn test_rounding() { let n = 1_i32 << 14; for i in -n..n { let u = i.rotate_right(11) as u32; let s = format!("{}", Hexf(f32::from_bits(u))); assert!(rounding_properties(&s).is_ok()); } } #[test] fn test_parse_any() { for k in -149..=127 { let s = format!("0x1p{k}"); let x = hf32(&s); let y = if k < 0 { 0.5f32.powi(-k) } else { 2.0f32.powi(k) }; assert_eq!(x, y); } let mut s = *b"0x.0000000p-121"; for e in 0..40 { for k in 0..(1 << 15) { let expected = f32::from_bits(k) * 2.0f32.powi(e); let x = hf32(std::str::from_utf8(&s).unwrap()); assert_eq!( x.to_bits(), expected.to_bits(), "\ e={e}\n\ k={k}\n\ x={x}\n\ expected={expected}\n\ s={}\n\ f32::from_bits(k)={}\n\ 2.0f32.powi(e)={}\ ", std::str::from_utf8(&s).unwrap(), f32::from_bits(k), 2.0f32.powi(e), ); for i in (3..10).rev() { if s[i] == b'f' { s[i] = b'0'; } else if s[i] == b'9' { s[i] = b'a'; break; } else { s[i] += 1; break; } } } for i in (12..15).rev() { if s[i] == b'0' { s[i] = b'9'; } else { s[i] -= 1; break; } } for i in (3..10).rev() { s[i] = b'0'; } } } // FIXME: this test is causing failures that are likely UB on various platforms #[cfg(all(target_arch = "x86_64", target_os = "linux"))] #[test] #[cfg(f128_enabled)] fn rounding() { let pi = std::f128::consts::PI; let s = format!("{}", Hexf(pi)); for k in 0..=111 { let (bits, status) = parse_any(&s, 128 - k, 112 - k, Round::Nearest).unwrap(); let scale = (1u128 << (112 - k - 1)) as f128; let expected = (pi * scale).round_ties_even() / scale; assert_eq!(bits << k, expected.to_bits(), "k = {k}, s = {s}"); assert_eq!(expected != pi, status.inexact()); } } #[test] fn rounding_extreme_underflow() { for k in 1..1000 { let s = format!("0x1p{}", -149 - k); let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else { unreachable!() }; assert_eq!(bits, 0, "{s} should round to zero, got bits={bits}"); assert!( status.underflow(), "should indicate underflow when parsing {s}" ); assert!(status.inexact(), "should indicate inexact when parsing {s}"); } } #[test] fn long_tail() { for k in 1..1000 { let s = format!("0x1.{}p0", "0".repeat(k)); let Ok(bits) = parse_hex_exact(&s, 32, 23) else { panic!("parsing {s} failed") }; assert_eq!(f32::from_bits(bits as u32), 1.0); let s = format!("0x1.{}1p0", "0".repeat(k)); let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else { unreachable!() }; if status.inexact() { assert!(1.0 == f32::from_bits(bits as u32)); } else { assert!(1.0 < f32::from_bits(bits as u32)); } } } // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to // hide them from the AST. #[cfg(f16_enabled)] macro_rules! f16_tests { () => { #[test] fn test_f16() { let checks = [ ("0x.1234p+16", (0x1234 as f16).to_bits()), ("0x1.234p+12", (0x1234 as f16).to_bits()), ("0x12.34p+8", (0x1234 as f16).to_bits()), ("0x123.4p+4", (0x1234 as f16).to_bits()), ("0x1234p+0", (0x1234 as f16).to_bits()), ("0x1234.p+0", (0x1234 as f16).to_bits()), ("0x1234.0p+0", (0x1234 as f16).to_bits()), ("0x1.ffcp+15", f16::MAX.to_bits()), ("0x1.0p+1", 2.0f16.to_bits()), ("0x1.0p+0", 1.0f16.to_bits()), ("0x1.ffp+8", 0x5ffc), ("+0x1.ffp+8", 0x5ffc), ("0x1p+0", 0x3c00), ("0x1.998p-4", 0x2e66), ("0x1.9p+6", 0x5640), ("0x0.0p0", 0.0f16.to_bits()), ("-0x0.0p0", (-0.0f16).to_bits()), ("0x1.0p0", 1.0f16.to_bits()), ("0x1.998p-4", (0.1f16).to_bits()), ("-0x1.998p-4", (-0.1f16).to_bits()), ("0x0.123p-12", 0x0123), ("0x1p-24", 0x0001), ("nan", f16::NAN.to_bits()), ("-nan", (-f16::NAN).to_bits()), ("inf", f16::INFINITY.to_bits()), ("-inf", f16::NEG_INFINITY.to_bits()), ]; for (s, exp) in checks { println!("parsing {s}"); assert!(rounding_properties(s).is_ok()); let act = hf16(s).to_bits(); assert_eq!( act, exp, "parsing {s}: {act:#06x} != {exp:#06x}\nact: {act:#018b}\nexp: {exp:#018b}" ); } } #[test] fn test_macros_f16() { assert_eq!(hf16!("0x1.ffp+8").to_bits(), 0x5ffc_u16); } }; } #[cfg(f16_enabled)] f16_tests!(); #[test] fn test_f32() { let checks = [ ("0x.1234p+16", (0x1234 as f32).to_bits()), ("0x1.234p+12", (0x1234 as f32).to_bits()), ("0x12.34p+8", (0x1234 as f32).to_bits()), ("0x123.4p+4", (0x1234 as f32).to_bits()), ("0x1234p+0", (0x1234 as f32).to_bits()), ("0x1234.p+0", (0x1234 as f32).to_bits()), ("0x1234.0p+0", (0x1234 as f32).to_bits()), ("0x1.fffffep+127", f32::MAX.to_bits()), ("0x1.0p+1", 2.0f32.to_bits()), ("0x1.0p+0", 1.0f32.to_bits()), ("0x1.ffep+8", 0x43fff000), ("+0x1.ffep+8", 0x43fff000), ("0x1p+0", 0x3f800000), ("0x1.99999ap-4", 0x3dcccccd), ("0x1.9p+6", 0x42c80000), ("0x1.2d5ed2p+20", 0x4996af69), ("-0x1.348eb8p+10", 0xc49a475c), ("-0x1.33dcfep-33", 0xaf19ee7f), ("0x0.0p0", 0.0f32.to_bits()), ("-0x0.0p0", (-0.0f32).to_bits()), ("0x1.0p0", 1.0f32.to_bits()), ("0x1.99999ap-4", (0.1f32).to_bits()), ("-0x1.99999ap-4", (-0.1f32).to_bits()), ("0x1.111114p-127", 0x00444445), ("0x1.23456p-130", 0x00091a2b), ("0x1p-149", 0x00000001), ("nan", f32::NAN.to_bits()), ("-nan", (-f32::NAN).to_bits()), ("inf", f32::INFINITY.to_bits()), ("-inf", f32::NEG_INFINITY.to_bits()), ]; for (s, exp) in checks { println!("parsing {s}"); let act = hf32(s).to_bits(); assert_eq!( act, exp, "parsing {s}: {act:#010x} != {exp:#010x}\nact: {act:#034b}\nexp: {exp:#034b}" ); } } #[test] fn test_f64() { let checks = [ ("0x.1234p+16", (0x1234 as f64).to_bits()), ("0x1.234p+12", (0x1234 as f64).to_bits()), ("0x12.34p+8", (0x1234 as f64).to_bits()), ("0x123.4p+4", (0x1234 as f64).to_bits()), ("0x1234p+0", (0x1234 as f64).to_bits()), ("0x1234.p+0", (0x1234 as f64).to_bits()), ("0x1234.0p+0", (0x1234 as f64).to_bits()), ("0x1.ffep+8", 0x407ffe0000000000), ("0x1p+0", 0x3ff0000000000000), ("0x1.999999999999ap-4", 0x3fb999999999999a), ("0x1.9p+6", 0x4059000000000000), ("0x1.2d5ed1fe1da7bp+20", 0x4132d5ed1fe1da7b), ("-0x1.348eb851eb852p+10", 0xc09348eb851eb852), ("-0x1.33dcfe54a3803p-33", 0xbde33dcfe54a3803), ("0x1.0p0", 1.0f64.to_bits()), ("0x0.0p0", 0.0f64.to_bits()), ("-0x0.0p0", (-0.0f64).to_bits()), ("0x1.999999999999ap-4", 0.1f64.to_bits()), ("0x1.999999999998ap-4", (0.1f64 - f64::EPSILON).to_bits()), ("-0x1.999999999999ap-4", (-0.1f64).to_bits()), ("-0x1.999999999998ap-4", (-0.1f64 + f64::EPSILON).to_bits()), ("0x0.8000000000001p-1022", 0x0008000000000001), ("0x0.123456789abcdp-1022", 0x000123456789abcd), ("0x0.0000000000002p-1022", 0x0000000000000002), ("nan", f64::NAN.to_bits()), ("-nan", (-f64::NAN).to_bits()), ("inf", f64::INFINITY.to_bits()), ("-inf", f64::NEG_INFINITY.to_bits()), ]; for (s, exp) in checks { println!("parsing {s}"); let act = hf64(s).to_bits(); assert_eq!( act, exp, "parsing {s}: {act:#018x} != {exp:#018x}\nact: {act:#066b}\nexp: {exp:#066b}" ); } } // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to // hide them from the AST. #[cfg(f128_enabled)] macro_rules! f128_tests { () => { #[test] fn test_f128() { let checks = [ ("0x.1234p+16", (0x1234 as f128).to_bits()), ("0x1.234p+12", (0x1234 as f128).to_bits()), ("0x12.34p+8", (0x1234 as f128).to_bits()), ("0x123.4p+4", (0x1234 as f128).to_bits()), ("0x1234p+0", (0x1234 as f128).to_bits()), ("0x1234.p+0", (0x1234 as f128).to_bits()), ("0x1234.0p+0", (0x1234 as f128).to_bits()), ("0x1.ffffffffffffffffffffffffffffp+16383", f128::MAX.to_bits()), ("0x1.0p+1", 2.0f128.to_bits()), ("0x1.0p+0", 1.0f128.to_bits()), ("0x1.ffep+8", 0x4007ffe0000000000000000000000000), ("+0x1.ffep+8", 0x4007ffe0000000000000000000000000), ("0x1p+0", 0x3fff0000000000000000000000000000), ("0x1.999999999999999999999999999ap-4", 0x3ffb999999999999999999999999999a), ("0x1.9p+6", 0x40059000000000000000000000000000), ("0x0.0p0", 0.0f128.to_bits()), ("-0x0.0p0", (-0.0f128).to_bits()), ("0x1.0p0", 1.0f128.to_bits()), ("0x1.999999999999999999999999999ap-4", (0.1f128).to_bits()), ("-0x1.999999999999999999999999999ap-4", (-0.1f128).to_bits()), ("0x0.abcdef0123456789abcdef012345p-16382", 0x0000abcdef0123456789abcdef012345), ("0x1p-16494", 0x00000000000000000000000000000001), ("nan", f128::NAN.to_bits()), ("-nan", (-f128::NAN).to_bits()), ("inf", f128::INFINITY.to_bits()), ("-inf", f128::NEG_INFINITY.to_bits()), ]; for (s, exp) in checks { println!("parsing {s}"); let act = hf128(s).to_bits(); assert_eq!( act, exp, "parsing {s}: {act:#034x} != {exp:#034x}\nact: {act:#0130b}\nexp: {exp:#0130b}" ); } } #[test] fn test_macros_f128() { assert_eq!(hf128!("0x1.ffep+8").to_bits(), 0x4007ffe0000000000000000000000000_u128); } } } #[cfg(f128_enabled)] f128_tests!(); #[test] fn test_macros() { #[cfg(f16_enabled)] assert_eq!(hf16!("0x1.ffp+8").to_bits(), 0x5ffc_u16); assert_eq!(hf32!("0x1.ffep+8").to_bits(), 0x43fff000_u32); assert_eq!(hf64!("0x1.ffep+8").to_bits(), 0x407ffe0000000000_u64); #[cfg(f128_enabled)] assert_eq!( hf128!("0x1.ffep+8").to_bits(), 0x4007ffe0000000000000000000000000_u128 ); } } #[cfg(test)] // FIXME(ppc): something with `should_panic` tests cause a SIGILL with ppc64le #[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] mod tests_panicking { extern crate std; use super::*; // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to // hide them from the AST. #[cfg(f16_enabled)] macro_rules! f16_tests { () => { #[test] fn test_f16_almost_extra_precision() { // Exact maximum precision allowed hf16("0x1.ffcp+0"); } #[test] #[should_panic(expected = "the value is too precise")] fn test_f16_extra_precision() { // One bit more than the above. hf16("0x1.ffdp+0"); } #[test] #[should_panic(expected = "the value is too huge")] fn test_f16_overflow() { // One bit more than the above. hf16("0x1p+16"); } #[test] fn test_f16_tiniest() { let x = hf16("0x1.p-24"); let y = hf16("0x0.001p-12"); let z = hf16("0x0.8p-23"); assert_eq!(x, y); assert_eq!(x, z); } #[test] #[should_panic(expected = "the value is too tiny")] fn test_f16_too_tiny() { hf16("0x1.p-25"); } #[test] #[should_panic(expected = "the value is too tiny")] fn test_f16_also_too_tiny() { hf16("0x0.8p-24"); } #[test] #[should_panic(expected = "the value is too tiny")] fn test_f16_again_too_tiny() { hf16("0x0.001p-13"); } }; } #[cfg(f16_enabled)] f16_tests!(); #[test] fn test_f32_almost_extra_precision() { // Exact maximum precision allowed hf32("0x1.abcdeep+0"); } #[test] #[should_panic] fn test_f32_extra_precision2() { // One bit more than the above. hf32("0x1.ffffffp+127"); } #[test] #[should_panic(expected = "the value is too huge")] fn test_f32_overflow() { // One bit more than the above. hf32("0x1p+128"); } #[test] #[should_panic(expected = "the value is too precise")] fn test_f32_extra_precision() { // One bit more than the above. hf32("0x1.abcdefp+0"); } #[test] fn test_f32_tiniest() { let x = hf32("0x1.p-149"); let y = hf32("0x0.0000000000000001p-85"); let z = hf32("0x0.8p-148"); assert_eq!(x, y); assert_eq!(x, z); } #[test] #[should_panic(expected = "the value is too tiny")] fn test_f32_too_tiny() { hf32("0x1.p-150"); } #[test] #[should_panic(expected = "the value is too tiny")] fn test_f32_also_too_tiny() { hf32("0x0.8p-149"); } #[test] #[should_panic(expected = "the value is too tiny")] fn test_f32_again_too_tiny() { hf32("0x0.0000000000000001p-86"); } #[test] fn test_f64_almost_extra_precision() { // Exact maximum precision allowed hf64("0x1.abcdabcdabcdfp+0"); } #[test] #[should_panic(expected = "the value is too precise")] fn test_f64_extra_precision() { // One bit more than the above. hf64("0x1.abcdabcdabcdf8p+0"); } // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to // hide them from the AST. #[cfg(f128_enabled)] macro_rules! f128_tests { () => { #[test] fn test_f128_almost_extra_precision() { // Exact maximum precision allowed hf128("0x1.ffffffffffffffffffffffffffffp+16383"); } #[test] #[should_panic(expected = "the value is too precise")] fn test_f128_extra_precision() { // Just below the maximum finite. hf128("0x1.fffffffffffffffffffffffffffe8p+16383"); } #[test] #[should_panic(expected = "the value is too huge")] fn test_f128_extra_precision_overflow() { // One bit more than the above. Should overflow. hf128("0x1.ffffffffffffffffffffffffffff8p+16383"); } #[test] #[should_panic(expected = "the value is too huge")] fn test_f128_overflow() { // One bit more than the above. hf128("0x1p+16384"); } #[test] fn test_f128_tiniest() { let x = hf128("0x1.p-16494"); let y = hf128("0x0.0000000000000001p-16430"); let z = hf128("0x0.8p-16493"); assert_eq!(x, y); assert_eq!(x, z); } #[test] #[should_panic(expected = "the value is too tiny")] fn test_f128_too_tiny() { hf128("0x1.p-16495"); } #[test] #[should_panic(expected = "the value is too tiny")] fn test_f128_again_too_tiny() { hf128("0x0.0000000000000001p-16431"); } #[test] #[should_panic(expected = "the value is too tiny")] fn test_f128_also_too_tiny() { hf128("0x0.8p-16494"); } }; } #[cfg(f128_enabled)] f128_tests!(); } #[cfg(test)] mod print_tests { extern crate std; use std::string::ToString; use super::*; #[test] #[cfg(f16_enabled)] fn test_f16() { use std::format; // Exhaustively check that `f16` roundtrips. for x in 0..=u16::MAX { let f = f16::from_bits(x); let s = format!("{}", Hexf(f)); let from_s = hf16(&s); if f.is_nan() && from_s.is_nan() { continue; } assert_eq!( f.to_bits(), from_s.to_bits(), "{f:?} formatted as {s} but parsed as {from_s:?}" ); } } #[test] #[cfg(f16_enabled)] fn test_f16_to_f32() { use std::format; // Exhaustively check that these are equivalent for all `f16`: // - `f16 -> f32` // - `f16 -> str -> f32` // - `f16 -> f32 -> str -> f32` // - `f16 -> f32 -> str -> f16 -> f32` for x in 0..=u16::MAX { let f16 = f16::from_bits(x); let s16 = format!("{}", Hexf(f16)); let f32 = f16 as f32; let s32 = format!("{}", Hexf(f32)); let a = hf32(&s16); let b = hf32(&s32); let c = hf16(&s32); if f32.is_nan() && a.is_nan() && b.is_nan() && c.is_nan() { continue; } assert_eq!( f32.to_bits(), a.to_bits(), "{f16:?} : f16 formatted as {s16} which parsed as {a:?} : f16" ); assert_eq!( f32.to_bits(), b.to_bits(), "{f32:?} : f32 formatted as {s32} which parsed as {b:?} : f32" ); assert_eq!( f32.to_bits(), (c as f32).to_bits(), "{f32:?} : f32 formatted as {s32} which parsed as {c:?} : f16" ); } } #[test] fn spot_checks() { assert_eq!(Hexf(f32::MAX).to_string(), "0x1.fffffep+127"); assert_eq!(Hexf(f64::MAX).to_string(), "0x1.fffffffffffffp+1023"); assert_eq!(Hexf(f32::MIN).to_string(), "-0x1.fffffep+127"); assert_eq!(Hexf(f64::MIN).to_string(), "-0x1.fffffffffffffp+1023"); assert_eq!(Hexf(f32::ZERO).to_string(), "0x0p+0"); assert_eq!(Hexf(f64::ZERO).to_string(), "0x0p+0"); assert_eq!(Hexf(f32::NEG_ZERO).to_string(), "-0x0p+0"); assert_eq!(Hexf(f64::NEG_ZERO).to_string(), "-0x0p+0"); assert_eq!(Hexf(f32::NAN).to_string(), "NaN"); assert_eq!(Hexf(f64::NAN).to_string(), "NaN"); assert_eq!(Hexf(f32::INFINITY).to_string(), "inf"); assert_eq!(Hexf(f64::INFINITY).to_string(), "inf"); assert_eq!(Hexf(f32::NEG_INFINITY).to_string(), "-inf"); assert_eq!(Hexf(f64::NEG_INFINITY).to_string(), "-inf"); #[cfg(f16_enabled)] { assert_eq!(Hexf(f16::MAX).to_string(), "0x1.ffcp+15"); assert_eq!(Hexf(f16::MIN).to_string(), "-0x1.ffcp+15"); assert_eq!(Hexf(f16::ZERO).to_string(), "0x0p+0"); assert_eq!(Hexf(f16::NEG_ZERO).to_string(), "-0x0p+0"); assert_eq!(Hexf(f16::NAN).to_string(), "NaN"); assert_eq!(Hexf(f16::INFINITY).to_string(), "inf"); assert_eq!(Hexf(f16::NEG_INFINITY).to_string(), "-inf"); } #[cfg(f128_enabled)] { assert_eq!( Hexf(f128::MAX).to_string(), "0x1.ffffffffffffffffffffffffffffp+16383" ); assert_eq!( Hexf(f128::MIN).to_string(), "-0x1.ffffffffffffffffffffffffffffp+16383" ); assert_eq!(Hexf(f128::ZERO).to_string(), "0x0p+0"); assert_eq!(Hexf(f128::NEG_ZERO).to_string(), "-0x0p+0"); assert_eq!(Hexf(f128::NAN).to_string(), "NaN"); assert_eq!(Hexf(f128::INFINITY).to_string(), "inf"); assert_eq!(Hexf(f128::NEG_INFINITY).to_string(), "-inf"); } } } libm-0.2.15/src/math/support/int_traits.rs000064400000000000000000000310001046102023000166100ustar 00000000000000use core::{cmp, fmt, ops}; /// Minimal integer implementations needed on all integer types, including wide integers. pub trait MinInt: Copy + fmt::Debug + ops::BitOr + ops::Not + ops::Shl { /// Type with the same width but other signedness type OtherSign: MinInt; /// Unsigned version of Self type Unsigned: MinInt; /// If `Self` is a signed integer const SIGNED: bool; /// The bitwidth of the int type const BITS: u32; const ZERO: Self; const ONE: Self; const MIN: Self; const MAX: Self; } /// Access the associated `OtherSign` type from an int (helper to avoid ambiguous associated /// types). pub type OtherSign = ::OtherSign; /// Trait for some basic operations on integers #[allow(dead_code)] pub trait Int: MinInt + fmt::Display + fmt::Binary + fmt::LowerHex + PartialEq + PartialOrd + ops::AddAssign + ops::SubAssign + ops::MulAssign + ops::DivAssign + ops::RemAssign + ops::BitAndAssign + ops::BitOrAssign + ops::BitXorAssign + ops::ShlAssign + ops::ShlAssign + ops::ShrAssign + ops::ShrAssign + ops::Add + ops::Sub + ops::Mul + ops::Div + ops::Rem + ops::Shl + ops::Shl + ops::Shr + ops::Shr + ops::BitXor + ops::BitAnd + cmp::Ord + From + CastFrom + CastFrom + CastFrom + CastFrom + CastFrom + CastInto + CastInto + CastInto + CastInto + CastInto { fn signed(self) -> OtherSign; fn unsigned(self) -> Self::Unsigned; fn from_unsigned(unsigned: Self::Unsigned) -> Self; fn abs(self) -> Self; fn from_bool(b: bool) -> Self; /// Prevents the need for excessive conversions between signed and unsigned fn logical_shr(self, other: u32) -> Self; /// Absolute difference between two integers. fn abs_diff(self, other: Self) -> Self::Unsigned; // copied from primitive integers, but put in a trait fn is_zero(self) -> bool; fn checked_add(self, other: Self) -> Option; fn checked_sub(self, other: Self) -> Option; fn wrapping_neg(self) -> Self; fn wrapping_add(self, other: Self) -> Self; fn wrapping_mul(self, other: Self) -> Self; fn wrapping_sub(self, other: Self) -> Self; fn wrapping_shl(self, other: u32) -> Self; fn wrapping_shr(self, other: u32) -> Self; fn rotate_left(self, other: u32) -> Self; fn overflowing_add(self, other: Self) -> (Self, bool); fn overflowing_sub(self, other: Self) -> (Self, bool); fn leading_zeros(self) -> u32; fn ilog2(self) -> u32; } macro_rules! int_impl_common { ($ty:ty) => { fn from_bool(b: bool) -> Self { b as $ty } fn logical_shr(self, other: u32) -> Self { Self::from_unsigned(self.unsigned().wrapping_shr(other)) } fn is_zero(self) -> bool { self == Self::ZERO } fn checked_add(self, other: Self) -> Option { self.checked_add(other) } fn checked_sub(self, other: Self) -> Option { self.checked_sub(other) } fn wrapping_neg(self) -> Self { ::wrapping_neg(self) } fn wrapping_add(self, other: Self) -> Self { ::wrapping_add(self, other) } fn wrapping_mul(self, other: Self) -> Self { ::wrapping_mul(self, other) } fn wrapping_sub(self, other: Self) -> Self { ::wrapping_sub(self, other) } fn wrapping_shl(self, other: u32) -> Self { ::wrapping_shl(self, other) } fn wrapping_shr(self, other: u32) -> Self { ::wrapping_shr(self, other) } fn rotate_left(self, other: u32) -> Self { ::rotate_left(self, other) } fn overflowing_add(self, other: Self) -> (Self, bool) { ::overflowing_add(self, other) } fn overflowing_sub(self, other: Self) -> (Self, bool) { ::overflowing_sub(self, other) } fn leading_zeros(self) -> u32 { ::leading_zeros(self) } fn ilog2(self) -> u32 { // On our older MSRV, this resolves to the trait method. Which won't actually work, // but this is only called behind other gates. #[allow(clippy::incompatible_msrv)] ::ilog2(self) } }; } macro_rules! int_impl { ($ity:ty, $uty:ty) => { impl MinInt for $uty { type OtherSign = $ity; type Unsigned = $uty; const BITS: u32 = ::ZERO.count_zeros(); const SIGNED: bool = Self::MIN != Self::ZERO; const ZERO: Self = 0; const ONE: Self = 1; const MIN: Self = ::MIN; const MAX: Self = ::MAX; } impl Int for $uty { fn signed(self) -> $ity { self as $ity } fn unsigned(self) -> Self { self } fn abs(self) -> Self { unimplemented!() } // It makes writing macros easier if this is implemented for both signed and unsigned #[allow(clippy::wrong_self_convention)] fn from_unsigned(me: $uty) -> Self { me } fn abs_diff(self, other: Self) -> Self { self.abs_diff(other) } int_impl_common!($uty); } impl MinInt for $ity { type OtherSign = $uty; type Unsigned = $uty; const BITS: u32 = ::ZERO.count_zeros(); const SIGNED: bool = Self::MIN != Self::ZERO; const ZERO: Self = 0; const ONE: Self = 1; const MIN: Self = ::MIN; const MAX: Self = ::MAX; } impl Int for $ity { fn signed(self) -> Self { self } fn unsigned(self) -> $uty { self as $uty } fn abs(self) -> Self { self.abs() } fn from_unsigned(me: $uty) -> Self { me as $ity } fn abs_diff(self, other: Self) -> $uty { self.abs_diff(other) } int_impl_common!($ity); } }; } int_impl!(isize, usize); int_impl!(i8, u8); int_impl!(i16, u16); int_impl!(i32, u32); int_impl!(i64, u64); int_impl!(i128, u128); /// Trait for integers twice the bit width of another integer. This is implemented for all /// primitives except for `u8`, because there is not a smaller primitive. pub trait DInt: MinInt { /// Integer that is half the bit width of the integer this trait is implemented for type H: HInt; /// Returns the low half of `self` fn lo(self) -> Self::H; /// Returns the high half of `self` fn hi(self) -> Self::H; /// Returns the low and high halves of `self` as a tuple fn lo_hi(self) -> (Self::H, Self::H) { (self.lo(), self.hi()) } /// Constructs an integer using lower and higher half parts #[allow(unused)] fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { lo.zero_widen() | hi.widen_hi() } } /// Trait for integers half the bit width of another integer. This is implemented for all /// primitives except for `u128`, because it there is not a larger primitive. pub trait HInt: Int { /// Integer that is double the bit width of the integer this trait is implemented for type D: DInt + MinInt; // NB: some of the below methods could have default implementations (e.g. `widen_hi`), but for // unknown reasons this can cause infinite recursion when optimizations are disabled. See // for context. /// Widens (using default extension) the integer to have double bit width fn widen(self) -> Self::D; /// Widens (zero extension only) the integer to have double bit width. This is needed to get /// around problems with associated type bounds (such as `Int`) being unstable fn zero_widen(self) -> Self::D; /// Widens the integer to have double bit width and shifts the integer into the higher bits #[allow(unused)] fn widen_hi(self) -> Self::D; /// Widening multiplication with zero widening. This cannot overflow. fn zero_widen_mul(self, rhs: Self) -> Self::D; /// Widening multiplication. This cannot overflow. fn widen_mul(self, rhs: Self) -> Self::D; } macro_rules! impl_d_int { ($($X:ident $D:ident),*) => { $( impl DInt for $D { type H = $X; fn lo(self) -> Self::H { self as $X } fn hi(self) -> Self::H { (self >> <$X as MinInt>::BITS) as $X } } )* }; } macro_rules! impl_h_int { ($($H:ident $uH:ident $X:ident),*) => { $( impl HInt for $H { type D = $X; fn widen(self) -> Self::D { self as $X } fn zero_widen(self) -> Self::D { (self as $uH) as $X } fn zero_widen_mul(self, rhs: Self) -> Self::D { self.zero_widen().wrapping_mul(rhs.zero_widen()) } fn widen_mul(self, rhs: Self) -> Self::D { self.widen().wrapping_mul(rhs.widen()) } fn widen_hi(self) -> Self::D { (self as $X) << ::BITS } } )* }; } impl_d_int!(u8 u16, u16 u32, u32 u64, u64 u128, i8 i16, i16 i32, i32 i64, i64 i128); impl_h_int!( u8 u8 u16, u16 u16 u32, u32 u32 u64, u64 u64 u128, i8 u8 i16, i16 u16 i32, i32 u32 i64, i64 u64 i128 ); /// Trait to express (possibly lossy) casting of integers pub trait CastInto: Copy { /// By default, casts should be exact. fn cast(self) -> T; /// Call for casts that are expected to truncate. fn cast_lossy(self) -> T; } pub trait CastFrom: Copy { /// By default, casts should be exact. fn cast_from(value: T) -> Self; /// Call for casts that are expected to truncate. fn cast_from_lossy(value: T) -> Self; } impl + Copy> CastFrom for T { fn cast_from(value: U) -> Self { value.cast() } fn cast_from_lossy(value: U) -> Self { value.cast_lossy() } } macro_rules! cast_into { ($ty:ty) => { cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); }; ($ty:ty; $($into:ty),*) => {$( impl CastInto<$into> for $ty { fn cast(self) -> $into { // All we can really do to enforce casting rules is check the rules when in // debug mode. #[cfg(not(feature = "compiler-builtins"))] debug_assert!(<$into>::try_from(self).is_ok(), "failed cast from {self}"); self as $into } fn cast_lossy(self) -> $into { self as $into } } )*}; } macro_rules! cast_into_float { ($ty:ty) => { #[cfg(f16_enabled)] cast_into_float!($ty; f16); cast_into_float!($ty; f32, f64); #[cfg(f128_enabled)] cast_into_float!($ty; f128); }; ($ty:ty; $($into:ty),*) => {$( impl CastInto<$into> for $ty { fn cast(self) -> $into { #[cfg(not(feature = "compiler-builtins"))] debug_assert_eq!(self as $into as $ty, self, "inexact float cast"); self as $into } fn cast_lossy(self) -> $into { self as $into } } )*}; } cast_into!(usize); cast_into!(isize); cast_into!(u8); cast_into!(i8); cast_into!(u16); cast_into!(i16); cast_into!(u32); cast_into!(i32); cast_into!(u64); cast_into!(i64); cast_into!(u128); cast_into!(i128); cast_into_float!(i8); cast_into_float!(i16); cast_into_float!(i32); cast_into_float!(i64); cast_into_float!(i128); libm-0.2.15/src/math/support/macros.rs000064400000000000000000000125501046102023000157250ustar 00000000000000/// `libm` cannot have dependencies, so this is vendored directly from the `cfg-if` crate /// (with some comments stripped for compactness). macro_rules! cfg_if { // match if/else chains with a final `else` ($( if #[cfg($meta:meta)] { $($tokens:tt)* } ) else * else { $($tokens2:tt)* }) => { cfg_if! { @__items () ; $( ( ($meta) ($($tokens)*) ), )* ( () ($($tokens2)*) ), } }; // match if/else chains lacking a final `else` ( if #[cfg($i_met:meta)] { $($i_tokens:tt)* } $( else if #[cfg($e_met:meta)] { $($e_tokens:tt)* } )* ) => { cfg_if! { @__items () ; ( ($i_met) ($($i_tokens)*) ), $( ( ($e_met) ($($e_tokens)*) ), )* ( () () ), } }; // Internal and recursive macro to emit all the items // // Collects all the negated cfgs in a list at the beginning and after the // semicolon is all the remaining items (@__items ($($not:meta,)*) ; ) => {}; (@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($tokens:tt)*) ), $($rest:tt)*) => { #[cfg(all($($m,)* not(any($($not),*))))] cfg_if! { @__identity $($tokens)* } cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* } }; // Internal macro to make __apply work out right for different match types, // because of how macros matching/expand stuff. (@__identity $($tokens:tt)*) => { $($tokens)* }; } /// Choose between using an arch-specific implementation and the function body. Returns directly /// if the arch implementation is used, otherwise continue with the rest of the function. /// /// Specify a `use_arch` meta field if an architecture-specific implementation is provided. /// These live in the `math::arch::some_target_arch` module. /// /// Specify a `use_arch_required` meta field if something architecture-specific must be used /// regardless of feature configuration (`force-soft-floats`). /// /// The passed meta options do not need to account for the `arch` target feature. macro_rules! select_implementation { ( name: $fn_name:ident, // Configuration meta for when to use arch-specific implementation that requires hard // float ops $( use_arch: $use_arch:meta, )? // Configuration meta for when to use the arch module regardless of whether softfloats // have been requested. $( use_arch_required: $use_arch_required:meta, )? args: $($arg:ident),+ , ) => { // FIXME: these use paths that are a pretty fragile (`super`). We should figure out // something better w.r.t. how this is vendored into compiler-builtins. // However, we do need a few things from `arch` that are used even with soft floats. select_implementation! { @cfg $($use_arch_required)?; if true { return super::arch::$fn_name( $($arg),+ ); } } // By default, never use arch-specific implementations if we have force-soft-floats #[cfg(arch_enabled)] select_implementation! { @cfg $($use_arch)?; // Wrap in `if true` to avoid unused warnings if true { return super::arch::$fn_name( $($arg),+ ); } } }; // Coalesce helper to construct an expression only if a config is provided (@cfg ; $ex:expr) => { }; (@cfg $provided:meta; $ex:expr) => { #[cfg($provided)] $ex }; } /// Construct a 16-bit float from hex float representation (C-style), guaranteed to /// evaluate at compile time. #[cfg(f16_enabled)] #[cfg_attr(feature = "unstable-public-internals", macro_export)] #[allow(unused_macros)] macro_rules! hf16 { ($s:literal) => {{ const X: f16 = $crate::support::hf16($s); X }}; } /// Construct a 32-bit float from hex float representation (C-style), guaranteed to /// evaluate at compile time. #[allow(unused_macros)] #[cfg_attr(feature = "unstable-public-internals", macro_export)] macro_rules! hf32 { ($s:literal) => {{ const X: f32 = $crate::support::hf32($s); X }}; } /// Construct a 64-bit float from hex float representation (C-style), guaranteed to /// evaluate at compile time. #[allow(unused_macros)] #[cfg_attr(feature = "unstable-public-internals", macro_export)] macro_rules! hf64 { ($s:literal) => {{ const X: f64 = $crate::support::hf64($s); X }}; } /// Construct a 128-bit float from hex float representation (C-style), guaranteed to /// evaluate at compile time. #[cfg(f128_enabled)] #[allow(unused_macros)] #[cfg_attr(feature = "unstable-public-internals", macro_export)] macro_rules! hf128 { ($s:literal) => {{ const X: f128 = $crate::support::hf128($s); X }}; } /// Assert `F::biteq` with better messages. #[cfg(test)] macro_rules! assert_biteq { ($left:expr, $right:expr, $($tt:tt)*) => {{ use $crate::support::Int; let l = $left; let r = $right; let bits = Int::leading_zeros(l.to_bits() - l.to_bits()); // hack to get the width from the value assert!( l.biteq(r), "{}\nl: {l:?} ({lb:#0width$x})\nr: {r:?} ({rb:#0width$x})", format_args!($($tt)*), lb = l.to_bits(), rb = r.to_bits(), width = ((bits / 4) + 2) as usize, ); }}; ($left:expr, $right:expr $(,)?) => { assert_biteq!($left, $right, "") }; } libm-0.2.15/src/math/support/mod.rs000064400000000000000000000015401046102023000152150ustar 00000000000000#[macro_use] pub mod macros; mod big; mod env; // Runtime feature detection requires atomics. #[cfg(target_has_atomic = "ptr")] pub(crate) mod feature_detect; mod float_traits; pub mod hex_float; mod int_traits; #[allow(unused_imports)] pub use big::{i256, u256}; pub use env::{FpResult, Round, Status}; #[allow(unused_imports)] pub use float_traits::{DFloat, Float, HFloat, IntTy}; pub(crate) use float_traits::{f32_from_bits, f64_from_bits}; #[cfg(f16_enabled)] #[allow(unused_imports)] pub use hex_float::hf16; #[cfg(f128_enabled)] #[allow(unused_imports)] pub use hex_float::hf128; #[allow(unused_imports)] pub use hex_float::{Hexf, hf32, hf64}; pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; /// Hint to the compiler that the current path is cold. pub fn cold_path() { #[cfg(intrinsics_enabled)] core::intrinsics::cold_path(); } libm-0.2.15/src/math/tan.rs000064400000000000000000000044141046102023000135070ustar 00000000000000// origin: FreeBSD /usr/src/lib/msun/src/s_tan.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_tan, rem_pio2}; // tan(x) // Return tangent function of x. // // kernel function: // k_tan ... tangent 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 tangent of `x` (f64). /// /// `x` is specified in radians. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tan(x: f64) -> f64 { let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; /* |x| ~< pi/4 */ if ix <= 0x3fe921fb { if ix < 0x3e400000 { /* |x| < 2**-27 */ /* raise inexact if x!=0 and underflow if subnormal */ force_eval!(if ix < 0x00100000 { x / x1p120 as f64 } else { x + x1p120 as f64 }); return x; } return k_tan(x, 0.0, 0); } /* tan(Inf or NaN) is NaN */ if ix >= 0x7ff00000 { return x - x; } /* argument reduction */ let (n, y0, y1) = rem_pio2(x); k_tan(y0, y1, n & 1) } libm-0.2.15/src/math/tanf.rs000064400000000000000000000046561046102023000136650ustar 00000000000000/* origin: FreeBSD /usr/src/lib/msun/src/s_tanf.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_tanf, rem_pio2f}; /* Small multiples of pi/2 rounded to double precision. */ const T1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ const T2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ const T3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ const T4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ /// The tangent of `x` (f32). /// /// `x` is specified in radians. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tanf(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 and underflow if subnormal */ force_eval!(if ix < 0x00800000 { x / x1p120 } else { x + x1p120 }); return x; } return k_tanf(x64, false); } if ix <= 0x407b53d1 { /* |x| ~<= 5*pi/4 */ if ix <= 0x4016cbe3 { /* |x| ~<= 3pi/4 */ return k_tanf(if sign { x64 + T1_PIO2 } else { x64 - T1_PIO2 }, true); } else { return k_tanf(if sign { x64 + T2_PIO2 } else { x64 - T2_PIO2 }, false); } } if ix <= 0x40e231d5 { /* |x| ~<= 9*pi/4 */ if ix <= 0x40afeddf { /* |x| ~<= 7*pi/4 */ return k_tanf(if sign { x64 + T3_PIO2 } else { x64 - T3_PIO2 }, true); } else { return k_tanf(if sign { x64 + T4_PIO2 } else { x64 - T4_PIO2 }, false); } } /* tan(Inf or NaN) is NaN */ if ix >= 0x7f800000 { return x - x; } /* argument reduction */ let (n, y) = rem_pio2f(x); k_tanf(y, n & 1 != 0) } libm-0.2.15/src/math/tanh.rs000064400000000000000000000026071046102023000136610ustar 00000000000000use super::expm1; /* tanh(x) = (exp(x) - exp(-x))/(exp(x) + exp(-x)) * = (exp(2*x) - 1)/(exp(2*x) - 1 + 2) * = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2) */ /// The hyperbolic tangent of `x` (f64). /// /// `x` is specified in radians. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tanh(mut x: f64) -> f64 { let mut uf: f64 = x; let mut ui: u64 = f64::to_bits(uf); let w: u32; let sign: bool; let mut t: f64; /* x = |x| */ sign = ui >> 63 != 0; ui &= !1 / 2; uf = f64::from_bits(ui); x = uf; w = (ui >> 32) as u32; if w > 0x3fe193ea { /* |x| > log(3)/2 ~= 0.5493 or nan */ if w > 0x40340000 { /* |x| > 20 or nan */ /* note: this branch avoids raising overflow */ t = 1.0 - 0.0 / x; } else { t = expm1(2.0 * x); t = 1.0 - 2.0 / (t + 2.0); } } else if w > 0x3fd058ae { /* |x| > log(5/3)/2 ~= 0.2554 */ t = expm1(2.0 * x); t = t / (t + 2.0); } else if w >= 0x00100000 { /* |x| >= 0x1p-1022, up to 2ulp error in [0.1,0.2554] */ t = expm1(-2.0 * x); t = -t / (t + 2.0); } else { /* |x| is subnormal */ /* note: the branch above would not raise underflow in [0x1p-1023,0x1p-1022) */ force_eval!(x as f32); t = x; } if sign { -t } else { t } } libm-0.2.15/src/math/tanhf.rs000064400000000000000000000016741046102023000140320ustar 00000000000000use super::expm1f; /// The hyperbolic tangent of `x` (f32). /// /// `x` is specified in radians. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tanhf(mut x: f32) -> f32 { /* x = |x| */ let mut ix = x.to_bits(); let sign = (ix >> 31) != 0; ix &= 0x7fffffff; x = f32::from_bits(ix); let w = ix; let tt = if w > 0x3f0c9f54 { /* |x| > log(3)/2 ~= 0.5493 or nan */ if w > 0x41200000 { /* |x| > 10 */ 1. + 0. / x } else { let t = expm1f(2. * x); 1. - 2. / (t + 2.) } } else if w > 0x3e82c578 { /* |x| > log(5/3)/2 ~= 0.2554 */ let t = expm1f(2. * x); t / (t + 2.) } else if w >= 0x00800000 { /* |x| >= 0x1p-126 */ let t = expm1f(-2. * x); -t / (t + 2.) } else { /* |x| is subnormal */ force_eval!(x * x); x }; if sign { -tt } else { tt } } libm-0.2.15/src/math/tgamma.rs000064400000000000000000000127141046102023000141750ustar 00000000000000/* "A Precision Approximation of the Gamma Function" - Cornelius Lanczos (1964) "Lanczos Implementation of the Gamma Function" - Paul Godfrey (2001) "An Analysis of the Lanczos Gamma Approximation" - Glendon Ralph Pugh (2004) approximation method: (x - 0.5) S(x) Gamma(x) = (x + g - 0.5) * ---------------- exp(x + g - 0.5) with a1 a2 a3 aN S(x) ~= [ a0 + ----- + ----- + ----- + ... + ----- ] x + 1 x + 2 x + 3 x + N with a0, a1, a2, a3,.. aN constants which depend on g. for x < 0 the following reflection formula is used: Gamma(x)*Gamma(-x) = -pi/(x sin(pi x)) most ideas and constants are from boost and python */ use super::{exp, floor, k_cos, k_sin, pow}; const PI: f64 = 3.141592653589793238462643383279502884; /* sin(pi x) with x > 0x1p-100, if sin(pi*x)==0 the sign is arbitrary */ fn sinpi(mut x: f64) -> f64 { let mut n: isize; /* argument reduction: x = |x| mod 2 */ /* spurious inexact when x is odd int */ x = x * 0.5; x = 2.0 * (x - floor(x)); /* reduce x into [-.25,.25] */ n = (4.0 * x) as isize; n = div!(n + 1, 2); x -= (n as f64) * 0.5; x *= PI; match n { 1 => k_cos(x, 0.0), 2 => k_sin(-x, 0.0, 0), 3 => -k_cos(x, 0.0), // 0 _ => k_sin(x, 0.0, 0), } } const N: usize = 12; //static const double g = 6.024680040776729583740234375; const GMHALF: f64 = 5.524680040776729583740234375; const SNUM: [f64; N + 1] = [ 23531376880.410759688572007674451636754734846804940, 42919803642.649098768957899047001988850926355848959, 35711959237.355668049440185451547166705960488635843, 17921034426.037209699919755754458931112671403265390, 6039542586.3520280050642916443072979210699388420708, 1439720407.3117216736632230727949123939715485786772, 248874557.86205415651146038641322942321632125127801, 31426415.585400194380614231628318205362874684987640, 2876370.6289353724412254090516208496135991145378768, 186056.26539522349504029498971604569928220784236328, 8071.6720023658162106380029022722506138218516325024, 210.82427775157934587250973392071336271166969580291, 2.5066282746310002701649081771338373386264310793408, ]; const SDEN: [f64; N + 1] = [ 0.0, 39916800.0, 120543840.0, 150917976.0, 105258076.0, 45995730.0, 13339535.0, 2637558.0, 357423.0, 32670.0, 1925.0, 66.0, 1.0, ]; /* n! for small integer n */ const FACT: [f64; 23] = [ 1.0, 1.0, 2.0, 6.0, 24.0, 120.0, 720.0, 5040.0, 40320.0, 362880.0, 3628800.0, 39916800.0, 479001600.0, 6227020800.0, 87178291200.0, 1307674368000.0, 20922789888000.0, 355687428096000.0, 6402373705728000.0, 121645100408832000.0, 2432902008176640000.0, 51090942171709440000.0, 1124000727777607680000.0, ]; /* S(x) rational function for positive x */ fn s(x: f64) -> f64 { let mut num: f64 = 0.0; let mut den: f64 = 0.0; /* to avoid overflow handle large x differently */ if x < 8.0 { for i in (0..=N).rev() { num = num * x + i!(SNUM, i); den = den * x + i!(SDEN, i); } } else { for i in 0..=N { num = num / x + i!(SNUM, i); den = den / x + i!(SDEN, i); } } return num / den; } /// The [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tgamma(mut x: f64) -> f64 { let u: u64 = x.to_bits(); let absx: f64; let mut y: f64; let mut dy: f64; let mut z: f64; let mut r: f64; let ix: u32 = ((u >> 32) as u32) & 0x7fffffff; let sign: bool = (u >> 63) != 0; /* special cases */ if ix >= 0x7ff00000 { /* tgamma(nan)=nan, tgamma(inf)=inf, tgamma(-inf)=nan with invalid */ return x + f64::INFINITY; } if ix < ((0x3ff - 54) << 20) { /* |x| < 2^-54: tgamma(x) ~ 1/x, +-0 raises div-by-zero */ return 1.0 / x; } /* integer arguments */ /* raise inexact when non-integer */ if x == floor(x) { if sign { return 0.0 / 0.0; } if x <= FACT.len() as f64 { return i!(FACT, (x as usize) - 1); } } /* x >= 172: tgamma(x)=inf with overflow */ /* x =< -184: tgamma(x)=+-0 with underflow */ if ix >= 0x40670000 { /* |x| >= 184 */ if sign { let x1p_126 = f64::from_bits(0x3810000000000000); // 0x1p-126 == 2^-126 force_eval!((x1p_126 / x) as f32); if floor(x) * 0.5 == floor(x * 0.5) { return 0.0; } else { return -0.0; } } let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 == 2^1023 x *= x1p1023; return x; } absx = if sign { -x } else { x }; /* handle the error of x + g - 0.5 */ y = absx + GMHALF; if absx > GMHALF { dy = y - absx; dy -= GMHALF; } else { dy = y - GMHALF; dy -= absx; } z = absx - 0.5; r = s(absx) * exp(-y); if x < 0.0 { /* reflection formula for negative x */ /* sinpi(absx) is not 0, integers are already handled */ r = -PI / (sinpi(absx) * absx * r); dy = -dy; z = -z; } r += dy * (GMHALF + 0.5) * r / y; z = pow(y, 0.5 * z); y = r * z * z; return y; } libm-0.2.15/src/math/tgammaf.rs000064400000000000000000000003341046102023000143360ustar 00000000000000use super::tgamma; /// The [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tgammaf(x: f32) -> f32 { tgamma(x as f64) as f32 } libm-0.2.15/src/math/trunc.rs000064400000000000000000000030511046102023000140540ustar 00000000000000/// Rounds the number toward 0 to the closest integral value (f16). /// /// This effectively removes the decimal part of the number, leaving the integral part. #[cfg(f16_enabled)] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn truncf16(x: f16) -> f16 { super::generic::trunc(x) } /// Rounds the number toward 0 to the closest integral value (f32). /// /// This effectively removes the decimal part of the number, leaving the integral part. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn truncf(x: f32) -> f32 { select_implementation! { name: truncf, use_arch: all(target_arch = "wasm32", intrinsics_enabled), args: x, } super::generic::trunc(x) } /// Rounds the number toward 0 to the closest integral value (f64). /// /// This effectively removes the decimal part of the number, leaving the integral part. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn trunc(x: f64) -> f64 { select_implementation! { name: trunc, use_arch: all(target_arch = "wasm32", intrinsics_enabled), args: x, } super::generic::trunc(x) } /// Rounds the number toward 0 to the closest integral value (f128). /// /// This effectively removes the decimal part of the number, leaving the integral part. #[cfg(f128_enabled)] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn truncf128(x: f128) -> f128 { super::generic::trunc(x) } #[cfg(test)] mod tests { #[test] fn sanity_check() { assert_eq!(super::truncf(1.1), 1.0); } } libm-0.2.15/src/math/truncf.rs000064400000000000000000000012321046102023000142210ustar 00000000000000/// Rounds the number toward 0 to the closest integral value (f32). /// /// This effectively removes the decimal part of the number, leaving the integral part. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn truncf(x: f32) -> f32 { select_implementation! { name: truncf, use_arch: all(target_arch = "wasm32", intrinsics_enabled), args: x, } super::generic::trunc(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 { #[test] fn sanity_check() { assert_eq!(super::truncf(1.1), 1.0); } } libm-0.2.15/src/math/truncf128.rs000064400000000000000000000004401046102023000144540ustar 00000000000000/// Rounds the number toward 0 to the closest integral value (f128). /// /// This effectively removes the decimal part of the number, leaving the integral part. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn truncf128(x: f128) -> f128 { super::generic::trunc(x) } libm-0.2.15/src/math/truncf16.rs000064400000000000000000000004341046102023000143730ustar 00000000000000/// Rounds the number toward 0 to the closest integral value (f16). /// /// This effectively removes the decimal part of the number, leaving the integral part. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn truncf16(x: f16) -> f16 { super::generic::trunc(x) }